ARM working mode and program invocation procedure

Source: Internet
Author: User
Tags exception handling versions

ARM's 8 modes of operation

USER

SYSTEM

SUPERVISOR chip reset and software execution SWI

FIQ

Irq

When SECURE MONITOR private data is executed, the user software calls the SMI to enter

ABORT access to memory data and instruction prefetch failure

UNDEFINED when executing an unrecognized instruction


system mode and user mode public registers, but has the ability to perform mode switching. So he is a bridge mode. SECURE MONITOR requires the coprocessor to start the module.

Vector Address Table

000000000 RESET SUPERVISOR

000000004 UNDEFINED Instruction UNDEFINED

000000008 Software interrupts SUPERVISOR

00000000C Abort Prefetche Abort

000000010 Abort DATA Abort

000000014 Reserver

000000018 IRQ IRQ

00000001C FIQ FIQ

Exception handling Priority Reset>data Abort>fiq>irq>prefeture abort>swi>undefined>secure MONITOR


The Apcs,arm procedure invocation Standard (ARM Procedure call standards) provides a mechanism for a compact authoring routine that can be interwoven with other routines. The most significant point is that there is no clear limit to where these routines come from. They can be compiled from C, Pascal, or it can be written in assembly language.

APCS defines the restrictions that are used on registers. conventions for using stacks. Pass/return parameters between function calls. The format of a stack-based structure that can be ' backtracking ' to provide a list of functions (and given parameters) from the point of failure to the entry of the program.

APCS is not a single given standard, but a series of standards that are similar but differ in specific conditions. For example, Apcs-r (for RISC OS) specifies that flags set when a function enters must be reset when the function exits. Under the 32-bit standard, you don't always know the entry flags (no USR_CPSR), so you don't need to restore them. As you might expect, there is no compatibility between the different versions. The code that wants to recover flags may behave erratically when they are not restored ...

If you develop an ARM-based system, you are not required to implement APCS. But it is recommended that you implement it, because it is not difficult to achieve, and can make you gain various benefits. However, if you want to write assembly code to be used with the compiled C connection (c is written in mixed with the assembly), you must use APCS. The compiler expects specific conditions that must be met in your join (add-in) code. A good example is APCS definition A1 to A4 can be destroyed, while V1 to V6 must be protected. Now I'm sure you're scratching your heads and talking to yourself, "What's a?" What is V? ". So first introduce the APCS-R register definition ...

  Register naming

APCS a different name for the registers we normally call R0 to R14. With the assembler preprocessor feature, you can define names like R0, but it's a good idea to learn to use APCS names when you're modifying code written by someone else.

Register name
reg# APCS meaning
R0 A1 Work Register
R1 A2 "
R2 a3 "
R3 a4 "
R4 v1 must be protected
R5 v2 "
R6 v3 "
R7 v4 "
R8 v5 "
R9 V6 "
R10 sl stack limit
R11 fp frame pointer
R12 IP Internal procedure Call Register
R13 sp stack pointer
R14 lr Connection Register
R15 pc program counter

IP is shorthand for instruction pointers.

These names are not defined by the standard Acorn objasm (version 2.00), but later versions of Objasm, and other assemblers (such as Nick Robert's ASM) define them. To define a register name, typically, you use the RN Macro Directive (Directive) at the beginning of the program:

A1     RN      0
A2     rn      1
a3     rn      2
    ...
etc... R13    rn      ,
SP     rn      ,
R14    rn      ,
LR     rn      R14
pc     RN      15

This example shows some important things: registers can define multiple names-you can define both ' R13 ' and ' SP '. Registers can be defined from the register previously defined-' LR ' is defined by a register called ' R14 '.
(For Objasm is correct, other assembler may not be the case) Design critical function calls should be fast, small, and easy (by the compiler) to optimize. Functions should be able to handle multiple stacks properly. Functions should be easy to write reentrant and relocatable code, mainly by separating the writable data from the code. But above all, it should be simple. This way assembler programmers can easily use its facilities, while debuggers can easily track the program.

  Consistency

The part of the program that follows APCS is called "consistent" when calling an external function. Following APCS (typically, compiler-generated programs) at all times during program execution is called "strict consistency." The agreement states that if you follow the correct entry and exit parameters, you can do whatever you need within your own function and remain consistent. This is necessary in some cases, such as when writing SWI camouflage (veneers), using many registers for actual SWI calls.

  Stack

Stacks are a list of linked ' frames ' that are linked by a thing called ' backtracking structure '. This structure is stored at the high end of each frame. Each chunk of the stack is allocated in descending order of address. The register SP always points to the lowest used address in the most current frame. This is in line with the traditional full descending stack. In Apcs-r, the Register SL holds a stack limit, and you decrement the SP to not lower it. Between the current stack pointer and the current stack, there should be no other APCS function to rely on, and when called, the function can set itself a stack.

There can be more than one stack area (chunk). They can be located at any address in memory and no specification is provided here. Typically, this will be used to provide multiple stacks for the same code when executed in reentrant mode, and an analogy is FileCore, which provides a simple set of ' state ' information and calls the same part of the code as required, to the currently available FileCore file system (ADFS, Ramfs, Idefs, scsifs, etc.) to provide services.

  Backtracking Structure

The register FP (frame pointer) should be 0 or the last structure in the list of stack backtracking structures, providing a way to trace the function of the call in reverse.

The backtracking structure is:

Address high-end
   Save code pointer        [FP]         FP point here
   return LR value [FP,          #-4] 
   return SP value [FP,          #-8] 
   return FP value          [FP, #-12]  Point to Next structure 
   [saved SL]
   [saved V6] [saved 
   v5] 
   [saved V4] 
   [Saved v3] 
   [Saved v2]
   [saved v1]
   [saved A4] ] [saved
   A3]
   [saved A2] [saved
   A1]
   [saved F7]                          three words
   [saved F6]                          three words
   [saved F5]                          three characters
   [saved F4]                          three-word
   
address low end

This structure contains 4 to 27 characters, which are optional values in square brackets. If they exist, they must exist in the order given (for example, A3 saved in memory can be saved F4, but a2-f5 cannot exist). Floating-point values are stored in ' internal format ' and occupy three characters (12 bytes).

The FP register points to the stack backtracking structure of the currently executing function. The return FP value should be zero, or a pointer to the stack backtracking structure established by the function that called the current function. The return FP value in this structure is a pointer to the stack backtracking structure that invokes the function that called the current function, and so on until the first function.

When the function exits, the return value of the connection, the return SP value, and the return FP value are loaded into the PC, SP, and FP.

 #include <stdio.h> void one (void);
  void (void);
  void zero (void);
     int main (void) {one ();
  return 0;
     } void One (void) {zero ();
     Both ();
  Return
     } void (void) {printf ("main...one...two\n");
  Return
  } void Zero (void) {return;
               When it outputs a message on the screen, the APCS backtracking structure will be: FP----> two_structure return link return SP
                                return FP----> One_structure ... return link              Return SP return FP----> Main_structure ...
                                                 Return link return SP return FP----> 0 ... 

So, we can examine the FP and see the structure of the function ' one ', which points to the structure of the function ' one ', which points to the structure of ' main ', which points to the zero end. In this way, we can reverse-trace the entire program and determine how we reached the current crash point. It is worth pointing out the ' zero ' function, because it has been executed and exited, and we are doing the printing behind it, so it was in the back of the structure, but it's not there anymore. It is also worth pointing out that it is unlikely that a APCS structure like the above will always be generated for a given code. The reason is that a function that does not call any other function does not require a full APCS header.


For a more detailed understanding, the following code is Norcroft C v4.00 generated for the above code ...

        Area |
        C $ $code |, code, READONLY IMPORT |__main| |x$codeseg|
        B |__main|
        DCB &6d,&61,&69,&6e DCB &00,&00,&00,&00 DCD &ff000008
        IMPORT |x$stack_overflow| 
        Export one export main main MOV IP, SP stmfd sp!, {fp,ip,lr,pc} SUB fp, IP, #4
        CMPS SP, SL bllt |x$stack_overflow|
        BL one MOV A1, #0 Ldmea fp, {fp,sp,pc}^ DCB &6f,&6e,&65,&00 DCD &ff000004 Export Zero export one MOV IP, SP stmfd sp!, {FP,IP,LR,
        PC} SUB FP, IP, #4 CMPS SP, sl bllt |x$stack_overflow|
BL Zero Ldmea fp, {FP,SP,LR} B, and IMPORT |_printf|
Both ADD A1, PC, #L000060-.-8 B |_printf| L000060 DCB &6d,&61,&69,&6e DCB &2e,&2e,&2e,&6f DCB &6e,&65,&2e,&2e DCB &2e,&74,&77,&6f DCB &0a,&00,&00,&00 Zero MOVS pc, LR is A |
        C $ $data | |x$dataseg|
 END

This example does not conform to the 32 system. The APCS-32 rule simply indicates that the logo does not need to be saved. So delete the LDM ' ^ ' suffix and delete the MOVS ' S ' suffix in function zero. The code is the same as the compiler that complied with 32-bit.

The Save Code pointer contains the instruction to set the backtracking structure (STMFD ...). Add 12 bytes to the address. Remember, for the 26-bit code, you need to remove the PSR to get the actual code address.

Now let's look at the first entry to the function: the PC always contains the next command to be executed. LR (always) contains the value to be loaded into the PC when exiting. It also contains PSR in the 26-bit bit code. The SP points to the current stack block (chunk) limit, or to the top of it. This is where the temporary data, registers, and similar things are copied. Under RISC OS, you have the option of at least 256 bytes to extend it. The FP is either zero or points to the most current part of the backtracking structure. The function arguments are laid out as described (below).

  actual Parameters

APCS does not define records, arrays, and similar patterns. Such languages are free to define how these activities are carried out. However, if your own implementation does not actually conform to the spirit of APCS, then the code from your compiler will not be allowed to connect with code from other compilers. Typical, the use of C language conventions. The first 4 integer arguments (or less!) are loaded into the A1-A4. Top 4 floating point arguments (or less!) are loaded into the f0-f3. Any other arguments, if any, are stored in memory and are pointed to by the word that precedes the value of the SP as it enters the function. In other words, the remaining parameters are pressed into the top of the stack. So to be simple. It is a good idea to define a function that accepts 4 or fewer parameters.

  function Exit

Exit the function by passing the return connection value to the program counter and: If the function returns a value less than or equal to one word size, place the value in A1. If the function returns a floating-point value, put it in F0. SP, FP, SL, V1-V6, and F4-f7 should be restored (if modified) to contain the values it holds when entering the function.
I tested intentional destruction registers, and the result was (often in completely different parts of the program) an unwanted and singular failure. These arguments for IP, LR, a2-a4, F1-F3, and incoming stacks can be destroyed.

In 32-bit mode, the PSR flag is not required to be protected from cross function calls. This must be done in 26-bit mode and secretly restored by transmitting LR to the PC (MOVS, or Ldmfd xxx^). It is not sufficient to re-load N, Z, C, and V from LR, and to protect these flags across functions.

build a stack backtracking structure

For a simple function (a fixed number of arguments, not reentrant), you can create a stack backtracking structure with the following instructions:

Function_name_label
        MOV     IP, SP
        stmfd   sp!, {fp,ip,lr,pc}
        SUB     fp, IP, #4

This fragment (from the compiled program above) is the most basic form. If you want to destroy other non-destructive registers, you should include them in this STMFD directive.

The next task is to check the stack space. If you don't need a lot of space (less than 256 bytes) You can use:

        CMPS    SP, sl
        bllt    |x$stack_overflow|

This is the way C version 4.00 handles overflow. In a later release, you will call |__rt_stkovf_split_small|.

And then do your own thing ...

Complete the exit with the following command:

        Ldmea   FP, {fp,sp,pc}^

Also, if you have other registers on the stack, reload them here as well. The reason for choosing this simple LDM exit mechanism is that it is easier and more reasonable than branching to a special function to exit the processor (handler).

An extension to this protocol used in backtracking is to embed the function name in the code. immediately preceding the function (and MOV IP, SP) should be:

        DCD     &ff0000xx

The ' xx ' here is the length of the function name string (including padding and Terminator). This string is a word-aligned, trailing-filled, and should be placed directly on the DCD &ff .... The front.

So a complete stack backtracking code should be:

        DCB     "My_function_name", 0, 0, 0, 0
        DCD     &ff000010
my_function_name
        MOV     IP, SP
        STMFD   sp!, {fp, IP, LR, pc}
        SUB     fp, IP, #4
        CMPS    sp, SL                    ; If you don't use stacks
        bllt    |x$stack _overflow|        ; You can omit
        ...
        deal with ... Ldmea   FP, {fp, SP, pc}^

To make it conform to the 32-bit system, simply omit the ' ^ ' of the last instruction. Note that you cannot use this code in a compiled 26-bit code. In fact, you can get rid of it, but it's not something I'm willing to bet on.

If you do not use stacks, and you do not need to save any registers, and you do not call anything, then it is not necessary to set the APCS block (but it is still useful for tracing problems during the debugging phase). In this case you can:

My_simple_function ...
        deal with ... MOVS    pc, LR

(again, use MOV for 32-bit APCS instead of MOVS, but don't risk connecting with 26-bit code).

  APCS Standard

In general, there are multiple versions of APCS (actually 16). We only care about what we might encounter on a RISC OS.

apcs-a
is Apcs-arthur, as defined by the early Arthur. It has been deprecated because it has different register definitions (it is some kind of heterogeneous for skilled RISC OS programmers). It is used for Arthur applications that run in USR mode. It should not be used. SL = R13, fp = R10, IP = R11, sp = R12, lr = R14, PC = R15. PRM (p4-411) says that "using R12 as an SP, rather than a more natural r13 on the system, is historic and precedes Arthur and RISC OS." The stack is fragmented and can be scaled as needed. 26-bit program counter. Floating-point arguments are not passed in the FP register. cannot be re-entered. The flag must be restored.

Apcs-r
is the Apcs-risc OS. For RISC OS applications operating in USR mode, or modules/handlers in SVC mode. SL = R10, fp = R11, IP = R12, sp = R13, lr = R14, PC = R15. It is the only most common version of APCS. Because all compiled C programs use Apcs-r. Explicit stack-limit checks. 26-bit program counter. Floating-point arguments are not passed in the FP register. cannot be re-entered. The flag must be restored.

Apcs-u
Is Apcs-unix,acorn's riscix use it. It is used for RISCIX applications (USR mode) or kernel (SVC mode). SL = R10, fp = R11, IP = R12, sp = R13, lr = R14, PC = R15. Implicit stack limit check (using SL). 26-bit

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.