Introduction to at&t assembly language and GCC Embedded Assembly
Release 0.1
Time 04/3/30
Email chforest_chang@hotmail.com
1 Differences Between at&t and Intel's assembly language syntax
1.1 case
1.2 operand assignment direction
1.3 prefix
1.4 indirect addressing syntax
1.5 suffix
1.6 commands
2 GCC Embedded Assembly
2.1 Introduction
2.2 Embedded Assembly example
2.3 syntax
2.3.1 Assembly statement Template
2.3.2 output
2.3.3 Input
2.3.4 restricted characters
2.3.5 damage description
2.4gcc how to compile embedded assembly code
3 postscript
This section introduces
Differences between at&t assembly language syntax and Intel assembly syntax, and then introduces the GCC Embedded Assembly syntax. To read this section, you must have intel
Assembly language basics.
1 Differences Between at&t and Intel's assembly language syntax
1.1
Case sensitivity
Intel commands use uppercase letters, while at&t
Use lowercase letters.
Example:
Intelat & T
MoV eax, ebxmovl % EBX, % eax
1.2
Direction of instruction operand value assignment
In INTEL syntax, the first represents the destination operand, the second represents the source operand, and the assignment direction is from right to left.
The first in AT&T syntax is the source operand, and the second is the destination operand. The direction is from left to right, which is natural.
Example:
INTELAT & T
Mov eax, EBXmovl % ebx, % eax
1.3
Command prefix
In INTEL syntax, the prefix is not required for registers and immediate numbers;
In AT&T, the Register must be prefixed with "%", and the immediate number must be prefixed with "___ FCKpd ___ 0 rdquo ;.
Example:
INTELAT & T
Mov eax, 1 movl $1, % eax
Symbol constants are directly referenced without a prefix, for example:
Movl value, % ebx
Value is a constant;
Add the prefix $ before the symbol to indicate the referenced symbol address,
For example
Movl $ value, % ebx
Is to put the value address in ebx.
Bus lock prefix "lock ":
Bus Lock operation. "Lock" prefix in Linux
Many core codes are used, especially SMP
Code. Other CPUs when the bus is locked
Cannot access the memory unit at the locked address.
The operation code of the remote jump instruction and sub-process call instruction uses the prefix "l", which is ljmp, lcall,
And the corresponding returned command pseudo lret.
Example:
INTELAT & T
Lcall $ secion: $ offset
Jmp far section: OFFSETljmp $ secion: $ offset
Ret far SATCK_ADJUSTlret $ stack_adjust
1.4 indirect addressing syntax
INTEL uses "[", "]", while AT&T "(", ")";
In addition, the syntax for processing complex operands is also different,
INTEL is Segreg: [base + index * scale + disp]
In AT&T, % segreg: disp (base, index, sale), where segreg
, Index, scale, and disp are optional. The Scale is not explicitly specified when the index is specified.
The default value is 1. Scale and disp do not need to be prefixed with "&".
INTELAT & T
Instr foo, segreg: [base + index * scale + disp] instr % segreg: disp (base, index, scale), foo
1.5
Instruction suffix
AT&T
In the syntax, the last letter of the most command operation code indicates the size of the operand, and "B" indicates byte.
(One byte); "w" indicates word (2, in bytes); "l" indicates long (4, in bytes ).
When Processing Memory operands in INTEL, there are similar syntaxes such:
Byte ptr, word ptr, and dword ptr.
Example:
INTELAT & T
Mov al, blmovb % bl, % al
Mov ax, bxmovw % bx, % ax
Mov eax, dword ptr [ebx] movl (% ebx), % eax
In the AT&T assembly instruction, the operand extension instruction has two suffixes: One specifying the length of the source operand and the other specifying the length of the target operand. AT&T's symbolic extension command is "movs", and the zero extension command is "movz"
"(Intel commands are" movsx "and" movzx "). Therefore, "movsbl % al, % edx" indicates the register al
The byte data is extended from byte to long, and the calculation result is stored in the register edx
. Below are some extensions of allowed operands:
L
Bl:, byte>-> long character l
Bw:, byte>-> word l
Wl:, word-> long word
The suffix after the jump instruction number indicates the jump direction, and "f" indicates the forward (forward ),
"B," indicates backward (back ).
Example:
Jmp 1f
Jmp 1f
1.6 commands
INTEL assembly and AT&T Assembly commands are basically the same, and the difference is only in syntax. For the syntax of each command, refer to I386Manual.
2 GCC Embedded Assembly
2.1 Introduction
Most kernel code uses C
Only a small part of the language is written in assembly language, such as Code related to a specific architecture and code that has a great impact on performance. GCC provides the Embedded Assembly function, which can directly embed assembly language statements in C code, greatly facilitating program design.
Simple embedded assembly is easy to understand
Example:
_ ASM __
_ Volatile _ ("hlt ");
"_ ASM _" indicates that the subsequent code is embedded assembly, and "ASM" is the alias of "_ ASM.
"_ Volatile _" indicates that the compiler should not optimize the code, and the subsequent commands will remain unchanged,
Volatile is its alias. The brackets contain Assembly commands.
2.2 Embedded Assembly example in Embedded Assembly, you can
The language expression is specified as the operand of the assembly instruction, and you do not have to worry about how
The register to which the value of the language expression is read, and how to write the calculation result back to C
Variable. You only need to tell the correspondence between the C language expression and the assembly instruction operand in the program. GCC
The code is automatically inserted to complete necessary operations.
To use embedded assembly, you must first compile the assembly instruction template, then associate the C language expression with the instruction operand, and tell
What are the restrictions of GCC on these operations. For example, in the following Assembly statement:
_ ASM _ violate __
("Movl % 1, % 0": "= r" (result): "M" (input ));
"Movl % 1, % 0" is the instruction template; "% 0" and "% 1" represent the operands of the instruction, called placeholders. Embedded Assembly relies on them
The language expression corresponds to the instruction operand. C is enclosed in parentheses after the instruction template.
Language Expressions. In this example, there are only two expressions: "result" and "input". They operate with commands in the order they appear.
Numbers "% 0", "% 1," correspond; Note the order: the first c expression corresponds to "% 0"; the second expression corresponds to "% 1"
", And so on, the number of operations can be up to 10, respectively, with" % 0 "," % 1 ".... "% 9," indicates. Before each operand
There is a string enclosed in quotation marks. The content of the string is the limitation or requirement on the operand. Before "result"
The restricted string is "= r", where "=" indicates that "result" is the output operand, "R"
"Indicates that the" result "needs to be associated with a general register. First, read the value of the operand into the Register, and then
Use the corresponding register in the instruction instead of the result itself.
Store the variable "result". On the surface, it seems like a command directly operates on "result". In fact, GCC
Implicit processing is performed, so that we can write less commands. The "R" in front of "input" indicates that the expression needs to be put
A register, which is then used in the instruction for calculation.
We put the embedded code above into a C source file, and then use gcc-C-S TO GET THE C
Compile code corresponding to the file source code, and then check the assembly code to see how GCC handles it.
The C source file is as follows. Note that this code has no practical significance and is only used as an example.
Extern int
Input, result;
Void test (void)
{
Input
= 1;
_ ASM _ volatile _ ("movl % 1, % 0 ":
"= R" (result): "R" (input ));
Return
;
}
The compilation code is as follows;
Line number code explanation
1
7
8 movl $1: input corresponds to the C language statement input = 1;
9 input, % eax
10 # comments inserted by APPGCC, indicating that the embedded assembly starts
11 movl % eax, % eax our Embedded Assembly Statement
12 # The comment inserted by NO_APPGCC indicates that the embedded assembly is complete.
13 movl % eax. The result is saved to the result variable.
14
-
18
......
From the assembly code, we can see that the 9th and 13th lines are GCC, and the code automatically added is GCC.
Determine how to deal with the C expression based on the qualified string. In this example, both expressions are specified as the "r" type, so use the command first:
Movl input, % eax
Read the input into the register % eax; GCC, and specify a register and the output variable result.
Related. This example is also % eax. Run the following command after obtaining the operation result:
Movl % eax, result
Write the register value back to the result of the C variable. From the assembly code above, we can see that
And input. The related registers are both % eax. GCC uses % eax to replace
% 0, % 1
Movl % eax, % eax
Obviously, this sentence can be avoided. This statement is not optimized, so it is not removed.
It can be seen that the relationship between the c expression or variable and the register is automatically handled by GCC. We only need to use the limit string to guide GCC.
How can this problem be solved. The limit character must match the instruction's requirements on the operand; otherwise, the resulting assembly code
There will be errors. You can change the two "R" in the above example to "M" (m, indicating that the operands are placed in the memory, rather than sent
In the memory), the result after compilation is:
Movl input, result
Obviously this is an invalid instruction, so the character string must match the instruction's requirements on the operand. For example, movl command
Allow register to register, count to register immediately, but do not allow memory to memory operations, so two operands
"M" cannot be used as the delimiter at the same time.
2.3 syntax
The embedded assembly syntax is as follows:
_ ASM __(
Assembly statement template:
Output part:
Input:
Damage description)
There are four parts: Assembly statement template, output part, input part, and destruction description part.
Open, the Assembly statement template is indispensable, and the other three parts are optional. If the latter part is used, and the former part is empty,
You also need to use the ":" format. The content of the corresponding part is blank. For example:
_ ASM _ volatile __(
"CLI ":
:
: "Memory ")
2.3.1 Assembly statement Template
An assembly statement template consists of a sequence of Assembly statements, separated by ";", "/N", or "/n/t.
The operands in the command can use placeholders to reference C language variables. A maximum of 10 operands can be placeholders with the following names: % 0, % 1 ..., % 9.
Operations that are expressed by placeholders in a command are always considered as long (4, in bytes),
The instruction can be a word or byte. When the operand is used as a word or byte, the default value is low or low.
The Byte operation can explicitly specify whether it is a low byte or a secondary byte. Insert a letter between % and serial number,
"B" indicates low bytes, and "H" indicates high bytes, for example, % H1.
2.3.2 output
The output part describes the output operations. Different Operation descriptors are separated by commas.
C language variable composition. The limited string of each output operand must contain "=", indicating that it is an output operand.
Example:
_ ASM _ volatile _ ("pushfl; popl % 0; CLI": "= G" (x ))
The descriptor string represents the constraints on the variable, so that GCC can determine based on these conditions
Assign registers, how to generate the connection between the necessary code Processing Instruction operands and C expressions or C variables.
2.3.3 Input
The input part describes the input operations. Different Operation descriptors are separated by commas (,).
A restricted string is composed of a C expression or a C 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 following example sets the NR bit of (* ADDR) to 1. The first placeholder % 0 and C, language variable ADDR
The second placeholder % 1 corresponds to the language variable Nr in C. Therefore, the Assembly statement code above is equivalent to the pseudocode below:
Btsl NR, ADDR, the two operands of this instruction cannot be all memory variables, so the qualified string of NR is specified as "ir ",
Associate NR with the immediate number or register, so that only ADDR is the memory variable in the two operands.
2.3.4 restricted characters
2.3.4.1 restricted character list
There are many types of restricted characters, some of which are related to a specific architecture. Here, only common restricted characters and i386 are listed.
Some common delimiters that may be used in. Their role is to instruct the compiler how to handle the subsequent C
The relationship between language variables and instruction operands, for example, whether to put variables in registers or in memory,
The following table lists frequently used qualified letters.
Category
Qualifier description General Register
"A" puts the input variable into eax
Here is a question: what if eax has been used?
It is actually very simple: because GCC knows that eax has been used, it inserts
Statement pushl % eax, save the eax content to the stack, and then add
Statement popl % eax to restore eax content
"B" puts the input variable into ebx
"C" puts input variables into ecx
"D" puts the input variable in edx
"S" puts the input variable into esi
"D" puts the input variable into edi
"Q" puts the input variables into one of eax, ebx, ecx, and edx.
"R" puts the input variables into a general register, that is, one of eax, ebx, ecx, edx, esi, and edi.
"A" combines eax and edx into A 64-bit register (uselong longs)
"M" memory variable
The "o" operand is a memory variable, but its addressing method is offset type, that is, base address addressing, or base address plus address change addressing.
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 mode is auto increment.
The "p" operand is a valid memory address (pointer)
Register or memory
"G" puts the input variable into one of eax, ebx, ecx, and edx or as the memory variable.
The "X" operand can be of any type.
Instant count
Immediate number between "I" 0-31 (for 32-bit displacement instructions)
"J" 0-63 "(for 64-bit displacement instructions)
"N" 0-255, the immediate number between (used for the out command)
"I" immediate count
"N" immediate number. Some systems do not support immediate numbers except words. These systems should use "n" instead of "I"
Match
"0", "1,"... "9"
It indicates that the operands restricted by it match a specified operand, that is, this operand is the specified operand,
For example, if "0" is used to describe the "% 1" operations, "% 1" references the "% 0" operations.
The difference between the 0-9 delimiter and "% 0"-"% 9" in the command. The former describes the operands, and the latter indicates the operands.
A detailed description is provided later. The output operand cannot use a register that is the same as the input operand.
Detailed descriptions are provided later.
Operand type
The "=" operand is only written in the instruction (the output operand)
The "+" operand is read/write type in the instruction (input/output operand)
Floating Point Number
"F"
Floating point register
"T" the first floating point register
"U" second floating point register
80387 of the "G" standard
Floating Point constant
% This operand can be switched to the next operand
For example, the two operands of addl can exchange order (of course, neither of them can be an immediate number)
# Partial comments. All letters from this character to the comma after it are ignored
* Indicates that if a register is selected, the subsequent letters are ignored.
Now let's continue to look at the example above,
"= M" (ADDR) indicates that ADDR is a memory variable ("m") and an output variable ("="); "Ir" (nr) indicates nr
An immediate number between 0 and 31 ("I") or a register operand ("r ").
2.3.4.2
Matching delimiter
I386
In the instruction set, the operands of many instructions are read-write (read-write operations refer to reading the original value before performing the operation, and finally
Write the result back to the operand), for example, addl % 1, % 0. It is used to save the sum of the operand % 0 and the operand % 1 to the operand % 0,
Therefore, the operand % 0 is the read-write operand. The GCC of the old version does not support this type of operands very well. It strictly applies the operands
It can be divided into two types: input and output, which are respectively placed in the input and output sections, without a separate part describing read/write operations,
Therefore, in GCC, the read/write operations must be described separately in the input and output sections, and the two must be correlated by matching the delimiter.
Note that only the same C variable is used in the input and output sections, but the filter character is not required. The generated code may be incorrect.
The cause is analyzed.
The matching qualifier is a digit: "0", "1 "...... "9,", respectively, indicates that the C expression restricted by it is
Placeholder % 0, % 1 ,...... The C variable corresponding to % 9 matches. For example, if "0" is used as the limit character of % 1
% 0 and % 1 indicate the same C variable.
Look at the code in the lower part to see why read/write operations should be described in the input and output sections respectively.
This example is used to calculate the sum of input + result and then store the result:
Extern int input, result;
Void test_at_t ()
{
Result = 0;
Input = 1;
_ Asm __
_ Volatile _ ("addl % 1, % 0": "= r" (result): "r" (input ));
}
The corresponding assembly code is:
Movl $0, _ result
Movl $1, _ INPUT
Movl _ input, % edX/APP
Addl % edX, % eax/no_app
Movl % eax, % edX
Movl % edX, _ result
Input is an input variable and needs to be placed in a register. The register allocated to it by GCC is % edX, before addl execution, % edX,
The content of is already the input value. It can be seen that for input variables or expressions that use the "r" restriction, GCC Inserts
The necessary Code reads their values into registers; the "M" variable does not need this step. Run addl after the input is read, obviously % eax
The value is incorrect. You must first read the value of result. Next, let's look at movl % eax, % edX, and movl % edX, _ result.
The function is to save the result back to the result. The registers allocated to the result are the same as those allocated to the input, which are both % EDX.
In summary, the following points can be summarized:
1. For input variables restricted by "r", GCC first allocates a register, then reads the value into the Register, and finally
Replace the placeholder with this register;
2. If the output variable restricted by "R" is used, GCC allocates a register and replaces the placeholder with this register,
However, before using this register, the variable value is not read into the register.
The value is useless and does not read into the register (probably because at&t assembler originated from the assembly language of the CISC architecture processor ).
In the CISC processor, the input and output of most commands are obviously separated, and unlike the operations like
Input and Output, for example, add r0, r1, r2, r0, and r1 are input, r2 is output, and input and output are separated,
The input and output operands are not used, so we can think that the original value of the operands corresponding to r2 is useless,
So there is no need to read the operand value into r2 first, because this is a waste of the CPU cycle of the processor), and finally GCC inserts the code,
Write the register value back to the variable;
3. After the registers used by the input variables use its commands at the last place, they can be used for other purposes, because
It is no longer in use. For example, % edx in the preceding example. After addl is executed, it is used as the register corresponding to the result.
Because the second line does not work with the embedded assembly command above, you need to read the result value before executing addl.
Register. You may just put the result in the input part (because the first one will ensure that the result
Read the register first ). The modified command is as follows (change the input delimiter from "r," to "m" for easier explanation "):
Extern int input, result;
Void test_at_t ()
{
Result = 0;
Input = 1;
_ Asm __
_ Volatile _ ("addl % 2, % 0": "= r" (result): "r" (result), "m" (input ));
}
It seems that the above Code works normally, because we know that % 0 and % 1 are related to result, we should use the same
Register, but GCC does not judge whether % 0 and % 1 are associated with the same c expression or variable (this is easy to generate and
Embedded Assembly Code), so the registers used by % 0 and % 1 may be different. Let's take a look at the assembly code.
Movl $0, _ result
Movl $1, _ INPUT
Movl _ result, % edX/APP
Addl _ input, % eax/no_app
Movl % eax, % edX
Movl % edX, _ result
Now the result value is read into the register % edX before addl is executed, but the addl instruction's operand % 0
It is % eax instead of % edX, which is different from expected because GCC assigns different variables to the output and input
GCC does not determine whether the two are related to the result. Later, we will explain how GCC translates embedded assembly.
It won't be surprising.
After the matching Delimiter is used, GCC knows that the corresponding operands should be placed in the same location (the same register or the same
Memory variable ). The code for matching restricted characters is as follows:
Extern int input, result;
Void test_at_t ()
{
Result = 0;
Input = 1;
_ ASM __
_ Volatile _ ("addl % 2, % 0": "= r" (result): "0" (result), "M" (input ));
}
The result in the input part is limited by the matching delimiter "0", indicating % 1 and % 0, representing the same variable,
The input part describes the input function of the variable, and the output part describes the output function of the variable.
Is read/write type. Because % 0 and % 1 indicate the same C variable, they are placed in the same location, whether in registers or in memory.
The compilation code is as follows:
Movl $0, _ result
Movl $1, _ INPUT
Movl _ result, % edX
Movl % edX, % eax/APP
Addl _ input, % eax/no_app
Movl % eax, % edX
Movl % edX, _ result
The result-related register is % EDX. The result is read from % edX to % eax before the command addl is executed,
After execution, you need to read the result from % eax into % EDX and save it to the result. Here we can see that GCC
Process a little bit of information about the output operations in the embedded assembly: addl does not use % edX, so it is not a simple result
Replace % 0 with the corresponding register % EDX. Instead, assign a register to execute the operation before storing the operation result.
Therefore, GCC first looks at the delimiter of the variable corresponding to the placeholder and finds that it is an output register variable,
Assign a register for it. At this time, no corresponding C variables are managed. Finally, GCC knows that the Register value should be written back to the variable,
At the same time, it finds that this variable is associated with % edx, so % edx is saved first, and then the variable is saved.
At this point, the reader should understand the meaning and usage of matching delimiters. In the new version of GCC, a restricted character "+" is added ",
It indicates that the operands are read/write type. GCC knows that the variable value should be read into the register first, then calculated, and finally written back to the variable.
You do not need to describe the variable in the input part.
Example;
Extern int input, result;
Void test_at_t ()
{
Result = 0;
Input = 1;
_ Asm __
_ Volatile _ ("addl % 1, % 0": "+ r" (result): "m" (input ));
}
Here, "+" is used to replace "=", and the description about result is removed from the input part. The resulting assembly code is as follows:
Movl $0, _ result
Movl $1, _ input
Movl _ result, % eax/APP
Addl _ input, % eax/NO_APP
Movl % eax, _ result
L2:
Movl % ebp, % esp
It is better to process than to use matching delimiters, saving several pieces of assembly code.
2.3.4.3 "&" delimiter
The delimiter "&" is used in many kernels. It indicates that the input and output operands cannot use the same registers,
This avoids many errors.
For example, the following code stores the return value of function foo In the ret variable:
_ Asm _ ("call foo; movl % edx, % 1",: "= a" (ret): "r" (bar ));
We know that the int type return value of the function is stored in % eax, but the gcc compilation result is that both the input and output use
Register % eax, as follows:
Movl bar, % eax
# APP
Call foo
Movl % ebx, % eax
# NO_APP
Movl % eax, ret
The result is obviously incorrect because GCC does not know that the value in % eax is what we want. To avoid this problem, use "&"
Qualifier, so that the bar will no longer use the % eax register because it has been specified by ret.
_ Asm _ ("call foo; movl % edx, % 1",: "= & a" (ret): "r" (bar ));
2.3.5 damage description
2.3.5.1 register corruption Descriptor
Generally, only one language is used for programming: advanced language or assembly language. The steps for compiling advanced languages are as follows:
L
Preprocessing;
L
Compile
L
Assembly
L
Link
Here we only care about Step 2 compilation (converting C code into assembly code): because all the code is written in advanced languages,
The compiler can recognize the functions of various statements. In the conversion process, all registers are determined by the compiler for allocation and use,
It has the ability to ensure that the use of registers will not conflict with each other; it can also be used as a buffer for variables, because the access of registers
The speed is many times faster than the memory. If you use all the assembly languages, programmers can only control the use of registers.
Ensure the correctness of registers. However, the mixed use of the two languages becomes more complicated, because the embedded assembly code can be directly used.
The compiler does not check the registers used by the embedded assembly code during conversion (because it is difficult to detect
Which registers are used by assembly instructions? For example, some commands implicitly modify registers. Sometimes embedded assembly code calls other sub-processes,
The sub-process also modifies the register), so a mechanism is required to notify the Compiler which registers we use (the programmer knows
Registers used in Embedded Assembly Code). Otherwise, the use of these registers may lead to errors. Modify the description section.
Can play this role. Of course, the registers specified in the input and output sections of the embedded assembly can be specified as "r", and the "g" type is determined by the compiler.
The de-allocated register does not need to be described in the destroy description section, because the compiler already knows.
The damage descriptor consists of a comma-separated string. Each string describes a situation, generally a register name.
There is also "memory ". For example, "% eax", "% ebx", and "memory.
Next, let's take a look at the example to figure out why we need to notify GCC of implicit in Embedded Assembly Code (it is called implicit because GCC does not know)
Registers used.
Some registers may be directly referenced in embedded assembly instructions. We already know that in AT&T-format assembly languages, registers
The name is prefixed with "%". To keep this "%" in the generated assembler
The reference must use "%" as the prefix of the register name. The reason is that "%" is used in asm, Embedded Assembly statements, and "/" is used in C
Therefore, "%" indicates "%" after conversion ".
Example (the descriptor is not modified ):
Int main (void)
{
Int input, output, temp;
Input = 1;
_ Asm _ volatile _ ("movl $0, % eax;/n/t
Movl % eax, % 1;/n/t
Movl % 2, % eax;/n/t
Movl % eax, % 0;/n/t"
: "= M" (output), "= m" (temp)/* output */
: "R" (input)/* input */
);
Return 0;
}
This Code uses % eax as a temporary register. The function is equivalent to C Code: "temp = 0; output = input ",
The compilation code is as follows:
Movl $1,-4 (% ebp)
Movl-4 (% ebp), % eax/APP
Movl $0, % eax;
Movl % eax,-12 (% EBP );
Movl % eax, % eax;
Movl % eax,-8 (% EBP);/no_app
Apparently, the register allocated to the input by GCC is also % eax. A conflict occurs, and the output value is always 0 rather than input.
Use the code after the destruction description:
Int main (void)
{
Int input, output, temp;
Input = 1;
_ ASM _ volatile __
("Movl $0, % eax;/n/T
Movl % eax, % 1;/n/T
Movl % 2, % eax;/n/T
Movl % eax, % 0;/n/t"
: "= M" (output), "= m" (temp)/* output */
: "R" (input)/* input */
: "Eax");/* descriptor */
Return 0;
}
Corresponding assembly code:
Movl $1,-4 (% ebp)
Movl-4 (% ebp), % edx/APP
Movl $0, % eax;
Movl % eax,-12 (% ebp );
Movl % edx, % eax;
Movl % eax,-8 (% ebp);/NO_APP
Through the destruction description section, GCC learned that % eax was used, so % edx was allocated to the input. Note the following when using Embedded Assembly:
Try to tell GCC as much information as possible to prevent errors.
If the command you use changes the condition register cc of the CPU, you need to add "cc" in the description section ".
2.3.5.2 memory destruction Descriptor
"Memory" is special and may be the most difficult part of Embedded Assembly. To explain it clearly, first introduce the compiler's
Optimization knowledge, then let's look at the C keyword volatile. Finally, let's look at the descriptor.
2.3.5.2.1 introduction to Compiler Optimization
The memory access speed is far less than the CPU processing speed. To improve the overall performance of the machine, hardware high-speed Cache is introduced on the hardware,
Accelerate access to memory. In addition, commands in modern CPUs are not necessarily executed in strict order, with no relevance.
The command line of the CPU can be fully utilized to improve the execution speed. The above is the hardware-level optimization.
Let's look at optimization at the software level: one is optimized by the programmer when writing the code, and the other is optimized by the compiler. Compiler
Common optimization methods include caching memory variables to registers and adjusting the command sequence to make full use of the CPU command line. Common
Is to re-Sort read/write commands.
When optimizing regular memory, these optimizations are transparent and efficient. The solution to the problem caused by Compiler Optimization or hardware re-sorting is from the hardware (or other processors) the memory barrier (memory barrier) must be set between operations executed in a specific sequence. linux provides a macro to solve the execution sequence problem of the compiler.
Void Barrier (void)
This function notifies the compiler to insert a memory barrier, but it is invalid for hardware. The compiled code will
All the modified values in the register are stored in the memory, and the data needs to be read again from the memory.
2.3.5.2.2 C-language keyword volatile
The C-language keyword volatile (note that it is used to modify the variable rather than the _ volatile _ mentioned above) indicates a variable.
The value may be changed externally, so the access to these variables cannot be cached in the Register, and needs to be re-accessed each time.
This keyword is often used in multi-threaded environments, because the same variable may be repaired by multiple threads when writing multi-threaded programs.
And the program synchronizes various threads through this variable. For example:
DWORD _ stdcall threadFunc (LPVOID signal)
{
Int * intSignal = reinterpret_cast