5.ARM assembly and C mixed assembly


ARM assembly and C hybrid assembly

  • 1. ATPCS standard

    • Concept

      • ATPCS: ARM-THUMB Procedure Call Standard (ARM-Thumb Procedure Call Standard)
    • Parameter rules

      • When passing function parameters, the first 4 parameters are passed through r0-r3, and more than 4 parameters are passed through the stack (Function parameters in C/C++ do not exceed 4)
      • When there are more than 4 parameters, it is implemented by pushing into the stack. The issue of compiler execution efficiency needs to be considered (Register efficiency is higher than memory)
    • Return value rules

      • The function return value is brought back through r0
      • #include <stdio.h>
        
        int function(void)
        {<!-- -->
        //Local variables: The stack area allocates space. When the function call ends, the stack space is released.
        int data = 100;
        return data;
        }
        
        int main(int argc, const char *argv[])
        {<!-- -->
        int a = function();
        printf("a = %d\
        ", a); //a: 100
        return 0;
        }
        Question: Why can data, as a local variable, still pass the value out?
            Get it through the register and put the value of data into the r0 register
        After the call, the returned value obtained can be read from r0
        The stack area space is released normally, and the value in the r0 register will not disappear.
        
        #include <stdio.h>
        
        int *function(void)
        {<!-- -->
        int data = 100;
        return &data;
        }
        
        int main(int argc, const char *argv[])
        {<!-- -->
        int *a = function();
        printf("*a = %d\
        ", *a); //*a: 100 or Segmentation fault (core dumped) segmentation fault (access to illegal address)
        return 0;
        }
        Question: Why does *a still print out as 100?
        The contents of the stack space are not released because the stack space has not been repartitioned.
        If other functions are called before printing, the stack space will be re-divided.
        
    • Stack mode rules

      • After the main function is compiled, it will be a label
  • 2. Advantages of hybrid programming

    • 1. C and assembly can be easily mixed

      • Achieve processor functions not possible in C
        Use new or unsupported instructions
        Produce more efficient Code
    • 2. Directly link variables and programs

      • Make sure it complies with the program calling specifications and input/output related symbols
    • 3. The compiler can also retain inline assembly

      • Most ARM instructions can be implemented
        Inline assembly code can be delivered by the compiler’s optimizer
  • 3. Assembly call C language

    • Operation

      • 1. Create a new test.c file in the project
      • 2. Add the test.c file to the project
      • 3. Write test.c code
      • 4. Compile and view
        • If no stack space operation is found, the compiler has optimized the code. The more optimization is done, the higher the program efficiency will be, but sometimes there is uncertainty.
        • Select optimization level
          • Magic Wand=>CC=>Optimization (default Level1 optimization)
          • default=>Default Level1, No Optimization=>O0, Level1=>O1, Level2(Speed)=>O2, Level2(Size)=>Os, Level3=>O3
          • Compiler optimization level
        • The operating system is set in C language, and the sp is set when creating a process
    • Example 1 (==pass in parameters<=4 >Register transfer)

      • //asm.s file
        .global_start
        
        _start:
        @Assign r0-r3 to O-3 respectively, and then pass them as parameters to func(int a, int b, int c, int d)
        @In the function, the sum is saved in sum, and then the function call ends and the sum is returned, and the return value is saved in the r2 register.
        ldr sp,=0x40001ff0 @Before operating the stack, the value of sp (Stack Pointer) must be set first
        mov r0,#0 @parameter 1
        mov r1,#1 @parameter 2
        mov r2,#2 @parameter 3
        mov r3,#3 @parameter 4
        \t
        bl sum @jump to sum function, the returned result is in r0
        mov r2,r0 @The return value is saved in the r2 register
        
        stop:
        b stop
        
        //test.c file
        int sum(int a, int b, int c, int d)
        {<!-- -->
        int sum = 0;
        sum = a + b + c + d;
        return sum;
        }
        
    • Example 2 (==Incoming parameters>4 >Stack transfer)

      • //asm.s file
        .global_start
        
        _start:
        @Based on Example 1, increase the number of parameters passed to 6
        ldr sp,=0x40001ff0 @Before operating the stack, the value of sp (Stack Pointer) must be set first
        mov r0,#0 @parameter 1
        mov r1,#1 @parameter 2
        mov r2,#2 @parameter 3
        mov r3,#3 @parameter 4
            mov r4,#4 @parameter 5
            mov r5,#5 @parameter 6
            
            stmfd sp!,{<!-- -->r4,r5} @Push r4 and r5 onto the stack (full stack decrement mode)
        \t
        bl sum @jump to sum function, the returned result is in r0
        mov r2,r0 @The return value is saved in the r2 register
        
        stop:
        b stop
        
        //test.c file
        int sum(int a, int b, int c, int d, int e, int f)
        {<!-- -->
        int sum = 0;
        sum = a + b + c + d + e + f;
        return sum;
        }
        
  • 4. Calling assembly in C program

    • Format:

      • asm(
        "Command 1\
        "
        "Command 2\
        "
        …
        :output list
        :Input list
        :Modify list (general register)
        );
        
      • Output list
        • int b,c;
          :"=r"(b),"=r"(c)
          
        • Output the value in the register to the variable
      • Input list
        • int a = 10;
          int b = 20;
          :"r"(a),"r"(b)
          
        • Input variables into registers
      • Modification list
        •  // r0, r1, r2 are used in the instruction to modify the list
          :"r0","r1","r2"
          
        • During inline assembly, modified registers
        • Why is there a modification list?
          • Because the compiler will translate the registers used in C language, it knows which registers it uses. After inline assembly, changing the value of the register requires the compiler to take it into consideration
      • If there are no three tables that can be left empty, the reference of the C variable is numbered from the output list to the input list: the first C variable %0, the second C variable %1,…
    • Example

      • //asm.s file
        .global_start
        
        _start:
        Calling assembly in @C program
        ldr sp,=0x40001ff0 @Before operating the stack, the value of sp (Stack Pointer) must be set first
        mov r0,#1
        mov r1,#2
        bl addTwoNum
        mov r2,r0
            
        stop:
        b stop
        
        //test.c file
        int addTwoNum(int a,int b)
        {<!-- -->
        int c;
        asm(
        "add r0,%1,%2\
        " //add r0,a,b ==> r0 = a + b
        "mov %0,r0\
        " //mov c,r0 ==> c = r0
        :"=r"(c) //Output list %0
        :"r"(a),"r"(b) //Input list %1,%2
        :"r0"
        );
        return c;
        }
        
      • C language cannot directly operate registers. If you want to do so, you must use inline assembly
    • IRQ enable example

      • To enable IRQ exception, you need to operate the CPSR register
      • //asm.s file
        .global_start
        
        _start:
        @Enable IRQ exception
        ldr sp,=0x40001ff0 @Before operating the stack, the value of sp (Stack Pointer) must be set first
        bl enable_irq
        mov r1,r0
            
        stop:
        b stop
        
        //test.c file
        int enable_irq(void)//Enable IRQ (I set to 0) to clear 0 and negate it with
        {<!-- -->
        int status;
        asm(
        "mrs r0,cpsr\
        " //Read the value in the CPSR register into r0
        "mov r1,#1\
        " //r1 = 1
        "bic r0,r0,r1,lsl #7\
        " //r0 = r0 & amp;~(r1 << 7) Set CPSR bit 7 (I) to 0 (default is 1)
        "msr cpsr,r0\
        " //Save the value of r0 into CPSR
        "mov %0,r0\
        " //status has its own number %0 in the code
        :"=r"(status) //Output status variable
        : //The input list is empty
        :"r0","r1"
        );
        return status;
        }
        
    • IRQ prohibition example

      • //asm.s file
        .global_start
        
        _start:
        @Enable IRQ exception
        ldr sp,=0x40001ff0 @Before operating the stack, the value of sp (Stack Pointer) must be set first
        bl enable_irq
            bl disable_irq
        mov r1,r0
            
        stop:
        b stop
                
        //test.c file
        int disable_irq(void)//Disable IRQ (I set to 1) If a certain position 1 needs to be used or
        {<!-- -->
        int status;
        asm(
        "mrs r0,cpsr\
        " //Read the value in the CPSR register into r0
        "mov r1,#1\
        " //r1 = 1
        "orr r0,r0,r1,lsl #7\
        " //r0 = r0 | (r1 << 7) Set CPSR bit 7 (I) to 1
        "msr cpsr,r0\
        " //Save the value of r0 into CPSR
        "mov %0,r0\
        " //status has its own number %0 in the code
        :"=r"(status) //Output status variable
        : //The input list is empty
        :"r0","r1"
        );
        return status;
        }
        
  • 5. volatile keyword

    • gcc optimization

      • Optimization ideas
        • If the memory data corresponding to this variable has been read into the register, when the memory data corresponding to this variable needs to be read again, the compiler has already stored the value in the register. When not optimized, the value is read from memory before each operation.
        • In order to improve efficiency, the compiler will directly use the value in the last register instead of reading it from memory
      • Optimization level
        • Level 1 optimization (O1)
        • Second level optimization [O2(Speed)/Os(Size)]
        • Three-level optimization (O3)
      • Problems arising from optimization
        • If the value in the memory has been changed by other execution units, and the optimized code reads the value from the register every time, it will cause the problem of inconsistency between the value in the register and the value in the memory ( Problems with global variables changes during multi-threading or interruption, interruption situations in bare metal development may change)
        • Solution: volatile keyword modifies parameters that do not require optimization
    • volatile effect

      • volatile (easy to change) modifies a variable to prevent compiler optimization (essential)
        Tell the compiler every time When using this variable, you must re-read the data from the memory where the variable is located
    • Interview questions

      • What should I pay attention to when using global variables in code with interrupt handler?
        • When defining global variables, you need to add volatile modification
  • 6. Exception handling

    • Exception

      • 5 exception modes (UDF, ABT, IRQ, FIRQ, SVC), 7 exception types
      • Reset and Software Interrupt both enter SVC management mode
        Data termination and prefetch termination both enter ABT termination mode
      • Exception vector table
    • Example (sickness)

      • After getting sick, you will enter the sick state (save the previous healthy state)
      • Go to the corresponding department to see a doctor
      • After seeing the patient, jump to the corresponding department for treatment
      • After treatment, return to the previous state and position
    • Things done automatically on ARM core hardware

      • When an exception occurs
        • (1)The value of CPSR is copied to the SPSR in exception mode
        • (2) Set the corresponding bit of CPSR
          • Change the processor state into ARM state
          • Change the processor mode to enter the corresponding exception mode
          • Set the interrupt disable bit to disable the corresponding interrupt (when an interrupt occurs)
        • (3) Save PC to LR in exception mode
        • (4) Set the PC value to the corresponding position in the exception vector table
      • When exception handling returns
        • Recovering the value of CPSR from SPSR in abnormal mode
        • Restore PC value from LR in abnormal mode
    • Exception handling flow chart

    • What programmers do

      • (1)Set the exception vector table (write a jump instruction in the exception vector table to jump to the specified exception handling function)
      • (2)Tell the base address of the ARM core exception vector table
        • [1]Before the Cortex-A series, the exception vector table could be stored at 0x0000,0000 (low address) or 0xffff,0000 (high address)
          c1 (register) of cp15 (coprocessor) ) determines whether the exception vector is stored at a high address or a low address
        • [2]After the Cortex-A series, the exception vector table can be stored in any location
          C12 (register) of cp15 (coprocessor) stores the base address of the exception vector table
      • (3)Write exception handling function
        • [1]Set sp register
        • [2] Push protection on general registers (r0~r12)
        • [3]Exception handling matters
        • [4]Exception return
          • A.Restore r0~r12 (pop)
          • B. Restore cpsr (spsr –> cpsr)
          • C. Restore pc (lr –> pc)
    • SoftWare Interrupt

      • Concept
        • Generate an exception trap and jump to the SWI hardware vector.
          The SWI handler can detect the SWI number and decide what action to take.
          Through the SWI mechanism, applications running in user mode can request the operating system to perform a series of privileged operations.
        • Software interruption
      • Grammar
        • SWI{< cond >} < SWI number >
          Soft interrupt number (SWI number) is translated into machine code after compilation, where 0~ Bit 23is the software interrupt number
      • What is the use of soft interrupt?
        • User space (non-privileged mode) enters kernel space (privileged mode)
        • Non-privileged mode cannot switch to privileged mode by itself, only through Exception
          • The arm platform uses the swi instruction, and the x86 uses the int instruction
          • Soft interrupt number distinguishes different system calls