Embedded ARM Assembly in C + +

Source: Internet
Author: User
Tags modifiers

The GCC compiler supports embedding arm assembly code directly in C or C + + code. Its basic format is very simple, roughly as follows:

__asm__ [__volatile__] (assembler template            : [Output operand list]                  /** /            : [input operand list]                   /** *           : [Clobbered Register list]               /* */           );

The first is the keyword "__asm__", in fact, can also be written as "ASM". However, "ASM" is not supported by all versions of the GCC compiler, and may conflict with variables or function names defined elsewhere in the program, so compatibility is a bit better with "__asm__".

The following is the "__volatile__" keyword, which is optional and does not allow the compiler to optimize the assembly instructions written later. In general, you write the assembly code must be designed to optimize their own, if the compiler is optimized, it is likely that the effect is not as good as not optimization, and there may be strange errors, so usually with this keyword. Similarly, "__volatile__" can also be written as "volatile", but may not be as good as compatibility.

Below, in parentheses, is the real assembly code, which consists of four main parts. The first one is the specific assembly code, which is required. The following three are some auxiliary parameters, which are optional.

Split between sections using the colon ":". If the previous section is unused, and the latter part is used, the preceding section also needs to be left blank with a colon. For example:

__asm__ __volatile__ ("msr cpsr,%0""R" (status));

As you can see, there is no second part in this example (the output parameter list), only the third part (input parameter list), but they have to leave a colon in the middle to split. At the same time, there is no part four, but there is no need to add a colon after the third part.

The following one by one explains the role of each part:

1) Assembly Code template

All assembly code must be enclosed in double quotation marks. If there is more than one line of assembly code, each statement is enclosed in double quotation marks, and a newline character ("\ n" or "\n\t") is appended to the code. This is done because GCC will pass the assembly code part as a string directly to the assembler, and with the newline character, the assembler will know exactly which strings represent a single assembly statement. At the same time, each assembly statement can be wrapped to add readability.

Its specific form is as follows:

" instruction 1\n\t "            " instruction 2\n\t "            ......            " Last instruction "            );

Because the assembly code section is required, even if a single line of assembly code is not available, you need to pass in an empty string (""), otherwise you will get an error.

2) Output sequence list and input operation list

Described earlier, the second and third sections represent the list of output operation lists and input operation lists respectively.

The input operand represents the C expression to be entered as the assembly code, and the output operand is the opposite, representing the C expression that will output the result after the assembly code has been processed. If you have more than one output or input expression, you need to separate them with commas (",").

You can apply the defined output operand and the input operand directly in the previous assembly code template using the percent sign ("%") followed by a number, 0 for the first operand defined, 1 for the second operand defined, and so on. Here's an example:

             __asm__ ("mov%0,%1, ror #1""=r " (Result)              " R " (value)            );

Here% 0 represents the first operand defined later, that is, the output operand, which represents the result variable in the C language. %1 represents the second operand defined, that is, the input operand, which represents the value variable in the C language. The effect is to move the value of the values one bit to the right and then save to result.

Each operand consists of three parts, the modifier (Modifier), the qualifier (Constraint), and the C expression, where modifiers are optional. The specific form is as follows:

" [Modifier]constraint " (C expression)

Modifiers and qualifiers are enclosed in double quotation marks, and C expressions are enclosed in parentheses. So what are these modifiers and qualifiers? What role does it have?

Let's go ahead and talk about the so-called qualifiers. As can be seen, the role of the operand here is the C language definition of variables and assembly language to use the variables to be used to one by one corresponding. But not all assembly instructions can accept any type of variable as an input or output variable, so the assembler needs to know exactly where these variables are used, thus helping to make some transformations before passing. Commonly used qualifiers have some of the following, and whether the assembly statement is arm or thumb, the definition of qualifiers will be different:

Qualifier under the arm instruction set under the thumb instruction set
F Floating-point Register F0...F7 N/A
H N/A Register R8...R15
G Floating-point constants immediate number N/A
H Same as G function N/A
I Immediate number used in data processing instructions Range is 0 ... Constants of 255
J Range is-4095 ... Index constants for 4095 Constants with a range of -255...-1
K And I act the same And I act the same
L And I act the same Range is-7 ... Constants of 7
L Same as R function Register R0...R7
M Range is 0 ... 32 or 2 of the power-squared constants Range is 0 ... Constants of multiples of 1020 of 4
M Memory address Memory address
N N/A Range is 0 ... Constants of 31
O N/A Range is-508 ... Constants of multiples of 508 of 4
R Universal Register R0...R15 N/A
W Vector floating-point register S0...S31 N/A
X Operands of any type Operands of any type

It looks complicated, but it's usually r,f and M.

OK, I'm done with qualifiers, here's a look at the modifier. The modifier is preceded by a qualifier and is optional, indicating that the operand is read-only if there is no modifier. This has no problem with the input operand, but it must be modified for the output operand. The answer is to use modifiers to modify the properties of this operand. Currently, three modifiers are defined in GCC, namely:

modifier meaning
= Write-only operands, typically used in the output operand
+ Readable and writable operands, which must be listed in the output operand
& Registers can only be used for output

So, as an output operand, just add "=" to the qualifier before you can.

In the assembly code, never modify the value of the input operand.

If you want a C variable to be both an input operand and an output operand, you can use the "+" qualifier, and the operand only needs to be listed in the output operand list. For example:

         __asm__ ("mov%0,%0, Ror #1""+r " (y)        );

The above example moves the value in the variable y by 1 bits. Because the input and output operands are one, the operands are both readable and writable, so the "+" modifier is added.

But the old version of GCC does not necessarily support the "+" modifier, and if you want to reach the previous input and output operands as a goal, you can use a workaround, and this workaround is supported by the new version of GCC. In fact, in qualifiers, you can also use a number, which refers to the operand defined earlier, 0 represents the first, 1 for the second, and so on. For example:

         __asm__ ("mov%0,%0, Ror #1""=r " (y)         "0"  (y)        );

If the GCC compiler supports this, the effect of this example is the same as in the previous example. In this case, a writable output variable is defined, and in the input variable list, it is explicitly indicated by the number 0 that the first operand defined earlier is also used as the input operand.

All right, we've introduced the usefulness of two modifiers, and the Last "&" is left. The previous example is explicitly required to use the same register for the output operand and the input operand, but sometimes the output operand must not be the same as the register used by the input operand. However, because of compiler optimizations, it is entirely possible to have the same register as both the input operand and the output operand. At this point, you can use the "&" modifier in the output operand to explicitly tell the compiler that the register that represents the output operand must not use a register that has already been used by the input operand. Here's an example:

 __asm__ __volatile__ ( ldr%0, [%1]\n\t   "  str%2, [%1, #4]   " :  
     
       "
      =&r  "   (RDV):   " r   " (&table),  r   "  (WDV):   " memory   

In this example, a table array is manipulated, the first number is read out to RDV, and the second number is changed to the value stored in WDV. At first glance there is nothing wrong, but what if the compiler is the same register to represent the input operand &table (% 1) and the output operand RDV (%0)? After the first statement is executed, the address of the table array is modified. Therefore, it is possible to add a "&" modifier to the output operand, forcing the output operand to be the same register as the input operand, which solves the problem. If the assembly code has not finished using the input register, the output operand is modified, it is necessary to use the "&" modifier, to ensure that no longer used.

3) Modify the Register list
In assembly instructions, it is possible to use some of the specified registers, but when executing your defined assembler, the specified register may have other uses, storing very important data. When your program is finished, the value of that register has been changed by you, which will definitely result in an execution error. Therefore, you must do the necessary backup and recovery actions before executing your program. However, the compiler does not parse your assembler code to find out which registers you have modified and need to recover, so you have to explicitly tell the compiler what registers you have modified. This is the function of modifying the list of registers.

For embedded inline arm assemblies, the values in this list are in the following three categories:

type function
R0...r15 Tells the compiler that the general register is modified in the assembly code R0...R15
Cc Tells the compiler that assembly code will cause changes in the CPU status bit
Memory Tells the compiler that assembly code will read or modify values stored in an address in memory

For "Memory", it does not mean that the register has been read or modified, but that the value in memory has been modified. For optimization purposes, before executing your assembler code, the compiler stores the values of some variables in the register and is not written to the actual memory. However, if your assembly code reads in-memory values, it is likely that the new value is still in the register, and the old value is stored in memory, which can cause errors. After adding "Memory", the compiler guarantees that it will be saved in the register before executing your code, and that all values not updated into memory are written to memory.

Each item in this list is enclosed in double quotation marks (""), separated by commas (",") between each item.

Embedded ARM Assembly in C + +

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.