The syntax of GCC embedding compilation

xiaoxiao2021-03-17  205

The syntax of GCC embedding compilation

The embedded compilation syntax is as follows:

__ASM __ (Compilation Specile Template: Output section: Enter the section: Destruction Description Parts)

A total of four parts: compilation language template, output section, input section, destruction section, each part use ":", compilation language template is essential, other three parts can be selected, if used, the back part is used, and front Part is empty, but also need to use ":", and the corresponding part is empty. E.g:

__ASM____volatile __ ("CLI"::: "memory")

1. Compilation State Template

The assembled statement template consists of the compilation statement sequence, and the statement is used to separate. ";", "/ N" or "/ n / n" separate. The number of operands in the command can use the placeholder reference C language variable, the operand placeholder is up to 10, the name is as follows:% 0,% 1, ...,% 9. Use the operand represented in the instruction, always treated as a long type (4 bytes), but the operation applied to it can be a word or byte according to the instruction, when the number of operands or bytes are used When the default is low or low byte. The byte operation can be explicitly indicated whether the low byte is or the secondary byte. The method is to insert a letter between% and serial numbers, "B" represents the low byte, "H" represents high bytes, such as% H1.

2, output part

The output section describes the output operand. Different operand descriptors are used in a comma, each operand descriptor consists of a defined string and a C language variable. The limit string of each output operator must contain "=" to indicate that he is an output operator.

example:

__ASM____volatile __ ("Pushfl; POPL% 0; CLI": "= g" (x))

The descriptor string represents the restriction condition of the variable so that the GCC can determine how to assign the register based on these conditions, how to generate the necessary code processing instruction operands and C expressions or C variables.

3, enter the part

The input section describes the input operand, and the different operand descriptors use a comma-opening, each operand descriptor consists of a defined string and a C language expression or C language variable.

example 1 :

__ASM__ __Volatile__ ("LIDT% 0":: "m" (real_mode_idt));

Example 2 (Bitops.h):

Static __inline__ void __set_bit (int NR, Volatile Void * Addr)

{

__ASM __ (

"BTSL% 1,% 0"

: "= M" (AddR)

: "IR" (NR));

}

The post-exemplary function is to set the NR bit of (* AddR) to 1. The first placeholder% 0 corresponds to the C language variable ADDR, and the second placeholder% 1 corresponds to the C language variable NR. Therefore, the above assembly statement code is equivalent to the following pseudo code equivalents: BTSL NR, ADDR, the two operands of the instruction cannot be all memory variables, so designate NR's qualified string to "IR", and the NR " Or the register is associated, so only addr is a memory variable in the two operands.

4, restriction character

4.1, restriction character list

There are many species that limit characters, and some are related to a particular architecture, which lists only some commonly used qualifiers that are commonly used in I386. Their role is to indicate how the compiler handles the relationship between the subsequent C language variables and the instruction operand.

Classification qualifier description

Universal Register "A" puts the input variable into EAX

Here is a problem: assuming that EAX has been used, what should I do?

Actually, it is very simple: because GCC knows that EAX has been used, it is assembled in this section.

Insert a statement pushl% EAX in the beginning, save the EAX content to the stack,

After the end of this code, add a statement POPL% EAX to restore EAX content.

"B" put the input variable into EBX

"C" puts the input variable into ECX

"D" puts the input variable into the EDX

"S" puts the input variable into the ESI

"D" puts the input variable into the EDI

"Q" puts the input variable into the EAX, EBX, ECX, EDX

"R" places the input variable into the universal register, which is Eax, EBX, ECX,

One of EDX, ESI, EDI

"A" synthesize EAX and EDX a 64-bit register (use long longs)

Memory "M" memory variable

The "O" operand is a memory variable, but its addressing method is an offset type.

It is also a base address, or a base address address address.

The "V" operand is a memory variable, but the addressing method is not an offset type.

"" The operand is a memory variable, but the addressing method is automatic increment.

"P" operand is a legal memory address (pointer)

The register or memory "G" puts the input variable into the EAX, EBX, ECX, EDX.

Or as a memory variable

The "X" operand can be any type

Quick number

The immediate number of "I" 0-31 (for 32-bit shift instructions)

The immediate number of "J" 0-63 (used for 64-bit shift instructions)

The immediate number of "n" 0-255 (for OUT command)

"I" immediately

"N" is immediately, some systems do not support the immediate number other than the word,

These systems should use "N" instead of "i"

Match "0", indicating that the number of operands that is limited is matched to a specified operand,

"1" ... that is, this operand is the specified number of operands, such as "0"

"9" describes the "% 1" operand, then "% 1" is actually

Is "% 0" operand, pay attention to 0-9 of the qualifier letter

The difference between "% 0" - "% 9" in the instruction, the former describes the operand,

The latter represents the operand.

& This output operand cannot be used and the same register is the same.

Operand type "=" operands are only written in the command (output operand)

" " Operands are read and write types in the command (input and output operand)

Floating point number "F" floating point register

"T" first floating point register

"U" second floating point register

"G" standard 80387 floating point constant

% This operand can be exchanged and the next operand

For example, the two operands of AddL can exchange order

(Of course, the two operands can not be an immediate number)

# Some comments, all letters between the comma from this character are ignored

* Indicates that if the register is selected, the following letters are ignored.

5, destroying the description

Destruction Descriptor For Notification Compiler Which registers or memory is used, consisting of a comma-opened string, each string describes a situation, typically a register name; except for the register, there is "Memory". For example: "% EAX", "% EBX", "Memory", etc.

"Special, it may be the most difficult part in embedded assembly. To explain it clearly, let's introduce it to the compiler's optimization knowledge, then look at the C keyword volatile. Finally, see this descriptor.

6, compiler optimization introduction

The memory access speed is far from the CPU processing speed, in order to improve the overall performance of the machine, introduce the hardware cache Cache on the hardware to accelerate access to memory. In addition, the execution of instructions in modern CPUs is not necessarily performed in order, without correlation instructions can be performed, to take advantage of the CPU's instruction pipeline, improve the execution speed. The above is the optimization of the hardware level. Look at the optimization of the software level: one is optimized by programmers when writing code, and the other is optimized by the compiler. The compiler optimized method is: cache memory variables to the register; adjust the command order to take advantage of the CPU instruction pipeline, commonly to reorder read and write instructions. These optimizations are transparent when optimizing conventional memory, and it is very efficient. The solution to the problem caused by compiler or hardware reordering is to set a memory barrier between the operations executed from the hardware (or other processor), and Linux provides a macro solution. Performing order of compiler. Void Barrier (Void)

This function notifies the compiler inserts a memory barrier, but the hardware is invalid, the compiled code will store all modified values ​​in the current CPU register into memory. When these data is required to read it again.

7, C language Keyword Volatile

C Language Keyword Volatile (Note that it is __volatile__) used to modify the variable instead of the above, indicating that the value of a variable may be changed externally, so access to these variables cannot be cached to the register, and each time you use Renew. This keyword is often used in multi-threaded environments, because when writing multithreaded programs, the same variable may be modified by multiple threads, and the program synchronizes each thread through the variable, for example:

DWORD __STDCALL ThreadFunc (LPVOID SIGNAL)

{

INT * INTSIGNAL = Reinterpret_cast (signal);

* INTSIGNAL = 2;

While (* INTSIGNAL! = 1)

Sleep (1000);

Return 0;

}

When the thread starts, set the INTSIGNAL to 2, then loop waiting

转载请注明原文地址:https://www.9cbs.com/read-129484.html

New Post(0)