Based on stm32mp157 linux development board ARM bare metal development tutorial 6: ARM assembly language programming (in serial)

Foreword:

At present, the ARM Cortex-A7 bare-metal development documents and videos have been upgraded twice and continuously updated to make the content richer and the explanation more detailed. The development platform used in the full text is the Huaqing Yuanjian FS-MP1A development board (STM32MP157 development board )

For the FS-MP1A development board, in addition to Cortex-A7 bare metal development, it also includes other series of tutorials, including Cortex-M4 development, FreeRTOS, Linux basic and application development, Linux system transplantation, Linux driver development , hardware design, artificial intelligence machine vision, Qt application programming, Qt comprehensive project actual combat, etc. In addition, it is planned to upgrade the documents and videos for the Linux system porting chapter and the Linux driver development chapter, so stay tuned!

For more information on the development board, please pay attention to Huaqing Vision Online Lab (WeChat ID: hqyjlab) to receive``

ARM  assembly language programming

Pseudo-ops supported by the GNU ARM  assembler

Overview of Pseudo-Operations

In the ARM assembly language program, there are some special instruction mnemonics. These mnemonics are different from the mnemonics of the instruction system and have no corresponding opcodes. These special instruction mnemonics are usually called pseudo-operation identifiers (directive ), and the operations they perform are called pseudo-operations. The role of the pseudo-operation in the source program is to complete various preparations for the assembler. These pseudo-operations only work during the assembly process. Once the assembly is completed, the mission of the pseudo-operation is completed.

In ARM's assembler, pseudo-operations mainly include symbol definition pseudo-operations, data definition pseudo-operations, assembly control pseudo-operations and miscellaneous pseudo-operations.

Data Definition Pseudo-Operations

The data definition pseudo-operation is generally used to allocate storage units for specific data, and at the same time complete the initialization of the allocated storage units. Common data definition pseudo operations are .byte, .short, .long, .quad, .float, .string, .asciz, .ascii, and .rept. The data definition pseudo-operation is as follows.

 

The assembly control pseudo-operation is used to control the execution flow of the assembler program. Commonly used assembly control pseudo-operations include the following.

1、 .if、.else、.endif

grammatical format

The .if, .else, and .endif pseudo-operations can decide whether to execute a sequence of instructions according to whether the condition is true or not. When the logical expression behind .if is true, execute the instruction sequence after .if, otherwise execute the instruction sequence after .else. Among them, there may be no .else and subsequent instruction sequences. At this time, when the logical expression behind .if is true, execute the instruction sequence, otherwise continue to execute the following instructions.

hint:

.if, .else, .endif directives can be nested.

The syntax format is as follows:

Example Code 46-1 Example of use

1 .if logical-expressing

2 …

3 .else

4 …

5 .endif logical-expression:

A logical expression used to determine the flow of instruction execution.

Use this instruction when there is an instruction in the program that needs to be executed when certain conditions are met. There is another form of this operation.

Example Code 46-2 Example of use

1 .if logical-expression

2 Instruction

3 .elseif logical-expression2

4 Instructions

5 .endif

This form avoids the nesting of the if-else form, making the program structure clearer and easier to read.

2、 .macro、.endm

grammatical format

The .macro pseudo-operation can define a piece of code as a whole, called a macro instruction, and then the code can be called multiple times through the macro instruction in the program. Among them, when the $ label is expanded, the label will be replaced with a user-defined symbol.

A macro action can take one or more arguments, which are replaced by the corresponding values ​​when the macro action is expanded.

The use and function of macro operations are somewhat similar to subroutines. Subroutines can provide modular programming, save storage space, and increase operating speed. However, when using the subroutine structure, the site needs to be protected, which increases the overhead of the system. Therefore, when the code is short and there are many parameters to be passed, the macro operation can be used instead of the subroutine.

The instruction sequence contained between .macro and .endm is called the macro definition body. The first line of the macro definition body should declare the prototype of the macro (including the macro name and the required parameters), and then it can be passed in the assembler Macro name to invoke the sequence of instructions. When the source program is compiled, the assembler expands the macro call, replaces the macro call in the program with the instruction sequence in the macro definition, and passes the value of the actual parameter to the formal parameter in the macro definition.

hint:

The .macro and .endm pseudo-operations can be nested.

The syntax format is as follows:

Example Code 46-3 Usage Example

1 .macro

2 {$label} macroname {$parameter{,$parameter} … }

3 ;code

4 .endm

Parameter Description

{$label}: When the $ label is expanded, the label will be replaced with a user-defined symbol. Usually, before a symbol use

"$" indicates that when the symbol is compiled by the assembler, use the corresponding value to replace the symbol.

{macroname}: The name of the defined macro.

{parameter}: The parameter of the macro command. When the macro instruction is expanded, it will be replaced with the corresponding value, similar to the parameters in the function.

Examples are as follows:

Example code 46-4 Example of use

1 .macro SHIFTLEFT a, b

2 .if \b < 0

3 MOV \a, \a, ASR #-\b

4 .exitm

5 .endif

6 MOV \a, \a, LSL #\b

7 .endm

.exitm is used to jump out from the macro definition, you only need to insert this instruction in the code of the macro definition.

When the subroutine code is relatively short and there are many parameters to be passed, the macro assembly technology can be used.

First define the macro through the .macro and .endm pseudo-operations, including the body code of the macro definition. The first line after the .macro pseudo-operation declares the prototype of the macro, which contains the name of the macro definition and the required parameters. It can be called by the name of the macro definition in assembly. When the source program is compiled, the assembler will expand each macro call, replace the name of the macro definition in the source program with the body of the macro definition, and replace the formal parameters of the macro definition with the actual parameter values.

3. Miscellaneous pseudo-operations

There are some other pseudo-operations in ARM assembly, which are often used in assembler programs, including the following.

 

Directives supported by the ARM  assembler

The ARM assembler supports ARM pseudo-instructions, which are translated into ARM or Thumb (or Thumb-2) instructions (or sequence of instructions) at the assembly stage. ARM directives include ADR, ADRL, LDR, etc.

ADR  directive

grammatical format

The ADR directive is a small range address read directive. The ADR pseudo-instruction reads the address value based on the relative offset of the PC or based on the relative offset of the register into the register. When the address value is byte-aligned, the value range is −255 to 255. When the address value is word-aligned, The value range is −1020 to 1020. When the address value is 16-byte aligned, its value range is larger.

The syntax format is as follows:

ADR{c}{.W} register,label

{c}: Optional command execution condition.

{.W}: Optional. Specifies the instruction width (supported by the Thumb-2 instruction set).

{register}: target register.

{label}: PC-based or expression with registers.

Instructions for use

The ADR directive is compiled into a single instruction by the assembler. The assembler usually uses the ADD instruction or the SUB instruction to realize the address loading function of the pseudo-operation. The assembler will report an error if the function of the ADR pseudo-instruction cannot be implemented with an instruction.

example

Sample code 46-5 Example of use

1 adr r1, init_stack

2 ;相当于下面的arm指令:

3 sub/add r1, pc, offset_to_init_stack

4 ...

5 init_stack: ...

LDR  directive

grammatical format

The LDR directive loads a 32-bit constant and an address into a register.

The syntax format is as follows:

LDR{cond}{.W} register,=[expr|label-expr]

{c}: Optional command execution condition.

{.W} specifies the instruction width (supported by the Thumb-2 instruction set).

{register}: target register.

{expr}: 32-bit constant expression. The assembler processes the LDR pseudo-instruction as follows according to the value of expr.

① When the address value represented by expr does not exceed the address value range of the MOV instruction or MVN instruction, the assembler replaces the LDR instruction with a pair of MOV and MVN instructions.

② When the address value of the instruction represented by expr exceeds the address range of the MOV instruction or MVN instruction, the assembler puts the constant into the data buffer pool, and uses a PC-based LDR instruction to read the constant.

{label-expr}

A program-related or declared extern expression. The assembler puts the value of the label-expr expression into the data buffer pool, and uses a program-dependent LDR instruction to fetch the value into a register.

When label-expr is declared as an extern expression, the assembler will insert a link relocation pseudo-operation in the object file, and the address will be generated by the linker at link time.

Instructions for use

Use the LDR instruction when the constant to be loaded exceeds the range of the MOV instruction or MVN instruction.

The address loaded by the LDR instruction is an absolute address, ie a PC-relative address.

When the data to be loaded cannot be directly loaded by the MOV instruction or the MVN instruction, the value must be put into the data cache pool first. At this time, there is a certain offset between the PC value at the LDR pseudo-instruction and the address of the target data in the data cache pool. limit. For ARM or 32-bit Thumb-2 instructions, the range is −4 to 4KB, and for Thumb or 16-bit Thumb-2 instructions, the range is 0 to 1KB. Read the constant 0xff0 into r1

Example code 46-6 Example of use

1 ldr r3,=0xff0 ;将常数 0xff0 读到 r1 中

2 ;相当于下面的 ARM 指令:

3 mov r3,#0xff0

Read the constant 0xfff into R1

Example Code 46-7 Example of use

1 ldr r1,=0xfff ;将常数0xfff读到r1中

2 ; 相当于下面的arm指令:

3 ldr r1,[pc,offset_to_litpool]

4 …

5 litpool .word 0xfff

 Read the place label address into R1

Example Code 46-8 Example of use

1 ldr r2,=place

2 ;相当于下面的arm指令:

3 ldr r2,[pc,offset_to_litpool]

4 …

5 litpool .word place

Program structure of ARM  assembly language

Assembly language program format

In the ARM (Thumb) assembly language program, you can use .section to segment, where each segment ends with the segment name or the end of the file, and these segments use default flags, such as a is an allowed segment, w is a writable segment, x is the execution segment.

In a section, we can define .text, .data, .bss subsections. From this we can know that segments can be divided into code segments, data segments and other storage segments. .text (text segment) contains program instruction codes; .data (data segment) contains fixed data, such as constants, strings ;.bss (uninitialized data segment) contains uninitialized variables, arrays, etc. When the program is long, it can be divided into multiple code segments and data segments, and multiple segments finally form an executable image when the program is compiled and linked document.

Sample code 46-9 Example of use

1 .section .data

2 <initialized data here>

3

4 .section .bss

5 <uninitialized data here>

6

7 .section .text

8 .globl _start

9 _start:

10 <instruction code goes here>

Procedure Call Standard AAPCS

In order to enable programs compiled by different compilers to call each other, certain rules must be specified for calls between subroutines. AAPCS is one such standard. The so-called AAPCS, its full English name is Procedure Call Standard for the ARM Architecture (AAPCS), that is, the ARM architecture procedure call standard. It is part of the ABI (Application Binary Interface (ABI) for the ARM Architecture (base standard) [BSABI]) standard.

The "--apcs" option can be used to tell the compiler to compile the source code into symbolic AAPCS call standard object code.

Notice:

Using the "--apcs" option does not affect the code generation, the compiler just places the corresponding attributes in each section to identify the AAPCS selected by the user

Attributes.

1. AAPCS-related compilation/assembly options

none: Specifies that the input file does not use AAPCS rules.

/interwork: Specifies that the input file conforms to the ARM/Thumb interwork standard.

/nointerwork: Specifies that the input file cannot use ARM/Thumb interwork. This is the compiler default option.

/ropi: Specifies that the input file is position-independent read-only.

/noropi: Specifies that the input file is a non-position-independent read-only file. This is the compiler default option.

/pic: Same as /ropi.

/nopic: Same as /noropi.

/rwpi: Specifies that the input file is a position-independent readable and writable file.

/norwpi: Specifies that the input file is a non-position-independent readable and writable file.

/pid:同/rwpi。

/nopid: Same as /norwpi.

/fpic: Specifies that the input file is compiled into position-independent read-only code. The address in the code is the FPIC address.

/swstackcheck: Use stack checking on input files during compilation.

/noswstackcheck: Do not use stack checking for input files during compilation. This is the compiler default option.

/swstna: The assembler uses option /swstna if the assembler does not care about data stack checking, and other programs linked with the assembler specify the option /swst or the option /noswst.

2. ARM register usage rules

AAPCS defines the ARM register usage rules as follows:

Parameters are passed between subroutines through registers R0, R1, R2, and R3. If there are more than 4 parameters, the extra parts are passed on the stack. The called subroutine does not need to restore the contents of registers R0-R3 before returning.

In subroutines, registers R4-R11 are used to store local variables. If some registers in the registers R4-R11 are used in the subroutine, the values ​​of these registers must be saved when the subroutine enters, and the values ​​of these registers must be restored before returning; for the registers not used in the subroutine, it is not necessary to these operations. In Thumb programs, usually only registers R4-R7 can be used to store local variables.

Register R12 is used as the scratch register between subroutines (used to save SP, and use this register to pop the stack when the function returns), denoted as ip. This usage rule is often used in linking code segments between subroutines.

Register R13 is used as a data stack pointer, denoted as sp. Register R13 cannot be used for other purposes in subroutines. The value of the register sp when entering the subroutine must be equal to the value when exiting the subroutine.

Register R14 is called the connection register and is denoted as lr. It is used to hold the return address of the subroutine. If the return address is saved in the subroutine, register R14 can be used for other purposes.

Register R15 is the program counter, denoted as pc. It cannot be used for other purposes.

The protection rules of ARM registers during function calls are shown in the figure.

 

3. Example of using AAPCS

Write a simple c program, through disassembly + single-step debugging, verify and learn AAPCS rules. You can open the project c_AAPCS project, where the content of main.c is as follows:

Example Code 46-10 AAPCS Usage Example

1 int add(int a, int b, int c, int d)

2 {

3 int e;

4 e = a+b+c+d;

5 return e;

6 }

7

8 int main()

9 {

10 int a,b,c,d,e;

11 a = 1;

12 b = 2;

13 c = 3;

14 d = 4;

15 e = add(a,b,c,d);

16

17 return 0;

18 }

By returning to the assembly window, you can see that in the main function, before calling the add subfunction, set R0=1, R1=2, R2=3, R3=4, and pass R0, R1, R2, R3 as parameters Give the subfunction add.

 

According to the AAPCS rules, the add subfunction directly uses R0, R1, R2, and R3, and does not need to protect these registers. But because R11 is used, according to the rules, it needs to be protected, so R11 is pushed into the stack for protection. The final return value is transmitted via R0.

 

Thinking: If the programming test is the case of 5 parameters.

ARM  pseudo-instruction experiment

Purpose

Master the basic use of ARM assembly language and the use of some pseudo-instructions;

Familiar with eclipse development tools to build assembly projects and simulations;

 Experimental principle

According to the usage syntax and functions of the RAM assembly language described above, write an assembly program to realize the operation of adding the data stored in two memories.

Experimental content

The assembler program is designed as follows:

Sample Code 46-11 Pseudo-instruction Case

1 .text

2 .global _start

3 _start:

4

5 .code 32

6

7

8 mov r1, #0

9

10 ldr r2,=myarray

11 loop:

12

13 ldr r3,[r2],#4

14 add r1,r1,r3

15 cmp r3,#0

16 bne loop

17

18 stop:

19 b stop

20

21 myarray:

22 .word 6

23 .word 24

24 .word 12

25 .word 0

26

27 .end

Experimental procedure

Import project source code

Please refer to Importing an Existing Project in the Importing an Existing Project chapter.

CD-ROM experiment source code path: [Data CD\Huaqing Vision-FS-MP1A Development Data-2020-11-06\02-Program Source Code\03-ARM Architecture and Interface Technology\Cortex-A7\h_test]

Experimental phenomena

Click the "icon below" step by step to view the changes of the Rn register.

 

 

The sum of the three data is stored in R1, and the final value of R1 is 42.

ARM  inline assembly experiment

Purpose

Master the basic usage of ARM assembly language and inline assembly usage;

Familiar with eclipse development tools to build assembly projects and simulations;

Experimental principle

The general format of GCC inline assembly:

asm(

code list

: list of output operators

: input operator list

: list of changed resources

);

In the code list, each assembly statement must be enclosed in " ".

Example Code 46-12 Inline Assembly Example

1 asm(

2 "add %0,%1,%2\n\t"

3 "mov r1,%1\n\t"

4 :"+r"(sum)

5 :"r"(a),"r"(b)

6 :"r0"

7 );

 Detailed case

Embedding assembly in C code requires the use of the asm keyword, usage asm();

 The part enclosed in " " quotes is the instruction part

 : The parameter output part, the return value of the function

 : The parameter input part, the formal parameter of the function

 : list of decorations, declaration part of inline assembly, resources to be changed

 "r" uses registers to store parameters

 "i" is an immediate value

 "m" a valid memory address

 "x" can only be input

 + Indicates that the parameter is readable and writable

 Not writing means that the parameter is read-only

 = means write only

 & can only do output

 %0 the first member of the output list and input list

 %1 is the 2nd member of the output list and input list

 %2 the 3rd member of the output list and input list

According to the syntax and functions of the ARM assembly language described above, write the inline assembly code in C language to achieve the least common multiple of the two parameters.

Experimental content

The experimental program design is as follows:

Example Code 46-13 Byte Swap

1 unsigned long ByteSwap(unsigned long val)

2 {

3 int ch;

4

5 asm volatile (

6 "eor r3, %1, %1, ror #16\n\t"

7 "bic r3, r3, #0x00ff0000\n\t"

8 "mov %0, %1, ror #8\n\t"

9 "eor %0, %0, r3, lsr #8"

10 : "=r" (ch)

11 : "0"(val)

12 : "r3"

13 );

14 }

15

16 int main(void)

17 {

18 unsigned long test_a = 0x1234,result;

19

20 result = ByteSwap(test_a);

21

22 printf("Result:%d\r\n", result);

23

24 return 0;

25 }

Experimental procedure

Import project source code

For related content, please refer to Importing an Existing Project Chapter Importing an Existing Project.

CD-ROM experiment source code path: [Data CD\Huaqing Vision-FS-MP1A Development Data-2020-11-06\02-Program Source Code\03-ARM Architecture and Interface Technology\Cortex-A7\h_inline]

Experimental results

Click the "icon below" to view the result in a single step.

 

 

Guess you like

Origin blog.csdn.net/u014170843/article/details/130687743