Inline assembly language in GCC (Intel i386 platform)

xiaoxiao2021-03-05  29

Inline assembly language in GCC (Intel i386 platform)

I. Statement Although the core code of Linux is written in C language, it is not avoidable to part of the assembly language. Some assembly language code is directly written in the source program, especially the launch code part of Linux; and some use the GCC's embedded assembly language in the C language program. This article briefly introduces the in-room embedded assembly language in GCC, mainly to help those friends who have only started reading Linux core codes faster.

The source of this article is the two info files of the GNU: as.info and gcc.info, if you think that the introduction in this article is not enough, you can check these two files. Of course, you can access these two files directly to get more authority. If you don't want to be confused by a lot of information in these two documents, I suggest you first read this article and then check out more authoritative information when necessary.

II. Introduction In the core code of Linux, there is still a considerable part of the assembly language code. If you want to read Linux code smoothly, you cannot bypass this part of the code. In the assembly language code used in Linux, there are two formats: one is to write directly to the form of assembly language source program. This part is mainly some of Linux startup code; another part is the use of GCC's embedded assembly language statement ASM is embedded in the C language code of Linux. This article mainly introduces the second form of assembly language code.

First, I will introduce the syntax format of the assembly language of the AS. Everyone knows that the format of the assembly language we have learned is mainly Intel style, and in the core code in Linux is the assembly language code of the AT & T format. It should be said that most people are not very good for the assembly language of this format. Learn, so I think it is necessary to introduce it.

Then, I mainly introduce the format of the GCC's embedded assembly language. The GCC's embedded assembly language provides a good way to directly embed the contractual instruction in the C language source program, which can directly control the description sequence formed, and a good interface with the C language, so in Linux code. This statement is used in many places.

Third. Qats & T's assembly language syntomworking format I think most of our people understand the assembly language of Intel format. However, in Linux core code, all assembly language instructions are written in compilation languages ​​in AT & T format. These two assembly languages ​​have great differences in grammar format:

1. In the assembly language of AT & T, use the '$' prefix to represent an immediate operand; and in the Intel format, the immediate operand means no precedent. For example: The following two statements are identical: * AT & T: Pushl $ 4 * Intel: Push 4

2. Aat & T and Intel's assembly language format, the position of the source operand and the target operand is as opposed. In the assembly language of Intel, the target operands are on the left of the source operation; in the assembly language of AT & T, the target operand is on the right of the source operand. For example: * AT & T: AddL $ 4,% EAX * Intel: Add Eax, 4

3. In the assembly language of At & T, the word length of the operand is determined by the last letter of the operation code help, the suffix 'b', 'w', 'L' represents the word length of the operands 8 bits, respectively. (Bytes, byte), 16 bits (word, Word), and 32-bit (long words, long words, long), and the word length in Intel format is represented by "Word PTR" or "Byte PTR". For example: * AT & T: MOVB FOO,% Al * Intel: MOV Al, Byte Ptr Foo4. In the AT & T assembly instruction, the instruction format directly far jump / call is "LCALL / LJMP $ Section, $ OFFSET", the same, remote The return command is "LRET $ Stack-Adjust"; and in the Intel format, the corresponding instructions are "Call / JMP Far Section: Offset" and "Ret Far Stack-Adjust".

1AT & T Compilation Instruction Operation Help Nammage Rules AT & T Language, the suffix character of the operation code help specifies the word length of the operating number in the instruction. The suffix letter 'b', 'w', 'L' represents the operand of the word length of 8 bits (bytes, byte), 16 bits (word, Word) and 32 bits (long words, long). If there is no specified word long suffix in the mission, there is no memory operand in the instruction, the assembler 'as' makes the corresponding suffix character according to the register operand specified in the instruction. Therefore, the following two instructions have the same effect (this is only a feature of the GNU assembler AS, and the AT & T 's Unix assembler will have a digital length assumption of the instruction of the word long suffix to 32 bits):

MOV% AX,% BX

MOVW% AX,% BX

Almost all operations in AT & T are the same name with the help notes in the Intel format, only a small part of the exception. Operating digital expansion instructions is one of the exceptions. In the AT & T assembly instruction, the operating number extension instruction has two suffix: a word length specified by the source operand, and the other specified the word length of the target. The basic help not of the AT & T symbol extension command is 'Movs', the basic help not of zero expansion instructions 'Movz' (the corresponding Intel instruction is 'MovsX' and 'Movzx'). Therefore, 'Movsbl% Al,% EDX' represents the symbol extension of bytes to the byte data in the register AL, and the calculation results are stored in the register EDX. Here is some allowed operand expansion suffix: * BL: byte-> long words * bw: bytes -> Word * WL: word -> long words There are some other type conversion instructions:

* Intel * AT & T (1) CBW CBTW Symbol Extension: Al-> AX (2) CWDE CWTL Symbol Extension: AX-> Eax (3) CWD CWTD Symbol Extension: AX-> DX: AX ⑷ CDQ CLTD Symbol Extension: EAX-> Edx: EAX

There is also a different name of a mission is a remote jump / calling instruction. In Intel format, the help not of the remote jump / call instruction is "Call / JMP FAR", and in the assembly language of AT & T, the corresponding instructions are "LCALL" and "LJMP".

2AT & T Names Named in the AT & T assembly language, the register operand always is prefixed as '%'. 80386 chip registers include: (1 )8 32-bit registers: '% EAX', '% EBX', '% ECX', '% EDX', '% EDI', '% ESI', '% EBP', '% ESP '(2 )8 16-bit registers:'% AX ','% bx ','% cx ','% dx ','% si ','% di ','% bp ','% sp '(3) 8-bit Register: '% AH', '% Al', '% BH', '% BL', '% CH', '% CL', '% DH', '% DL' ⑷6 segment register: '% cs' , '% DS', '% ES', '% SS', '% FS', '% GS' ⑸ 3 control registers: '% CR0', '% CR1', '% CR2' ⑹6 Test Register: ' % DB0 ','% DB1 ','% DB2 ','% DB3 ','% DB6 ','% DB7 '⑺ 2 test registers:'% tr6 ','% TR7 '⑻8 floating point register stack:' % ST (0) ','% ST (1) ','% ST (2) ','% ST (3) ','% ST (4) ','% ST (5) ','% ST (6) ','% ST (7) '* Note: I don't know these registers, which are just taken from the as.info document. If you really need a message named, I want to refer to the source file of the machine description of the corresponding GNU tool.

The operation code prefix in 3AT & T (1) Segment beyond the prefix 'CS', 'DS', 'ES', 'SS', 'FS', 'GS': When the memory operand is performed in the assembler: Memory-Operand quote Automatically couple the corresponding segment transcendence prefix. (2) Opective number / address size prefix 'DATA16', 'addr16': These prefix converts 32-bit operands / addresses to 16-bit operands / address. (3) Bus Lock Prefix 'Lock': Bus Lock Operation. The 'Lock' prefix is ​​used in the Linux core code, especially in the SMP code. ⑷ Coprocessor Wait for Prefix 'Wait': Waiting for the Coorders to complete the current operation. ⑸ Instruction Repeat Prefix 'REP', 'REPE': The execution of the instructions in the serial operation.

The format of the memory operand reference is as follows:

Section: [Base Index * Scale DISP] In the assembly language of AT & T, the application format of memory operations is like this:

Section: DISP (Base, INDEX, Scale)

Here are some examples of memory operations:

* AT & T * Intel (1) -4 (% EBP) [EBP-4] (2) Foo (,% EAX, 4) [Foo EAX * 4] (3) Foo (, 1) [foo] ⑷% GS: foo GS: foo Yes, the memory operand in the absolute jump / call instruction must be the most prefixed in '*', otherwise AS always assume that this is a relative jump / call command.

The jump instruction AS assembler in 5at & t will automatically optimize the jump instruction, always use as small as possible. Jump offset. If the 8-bit offset cannot meet the requirements, the AS uses a 32-bit offset. The AS assembler has no 16-bit jump offset, so use the 'AddR16' prefix for the jump instruction. Invalid.

There are also some jump instructions to support only 8-bit jump offset, including: 'JCXZ', 'JECXZ', 'LOOP', 'LOOPZ', 'LOOPE', 'LOOPNZ' and 'LOOPNE'. So, use these instructions in the assembly program of the AS may be wrong. (Fortunately, GCC does not use these instructions)

The simplicity of the AT & T assembly language syntax is similar, some of which are unique to the AS. In the Linux core code, it does not involve all the syntax rules mentioned above, two of which are especially important: First, the prefix '%' is used when the register is referenced; second, AT & T assembly language Source The position of the operand and the target operand is opposite to the syntax of our familiar Intel.

Four .GCC's embedded assembly language statement ASM uses GCC's ASM statement, you can directly embed the assembly language instructions in the C language code, and you can also specify the operand used by the compilation instruction using the C language expression. This feature provides great convenience.

To use this feature, you must first write a template for assembly instructions (this template is a bit similar to the instruction template in the machine description file), then specify a defined string for each operand. For example: extern __INLINE__ VOID CHANGE_BIT (INT NR, VOLATILE VOID * AddR) {

__asm__ __volatile __ (Lock_PREFIX

"BTCL% 1,% 0"

: "= M" (AddR)

: "IR" (nr));} The above function:

Lock_prefix: This is a macro, if __smp__, extension is "LOCK;", used to specify the bus lock prefix, otherwise it is expanded to "".

Addr: This is also a macro, defined as (* (volatile struct __dummy *) addr)

"BTCL% 1,% 0": This is the embedded assembly language command, BTCL is the instruction opcode,% 1,% 0 is the placeholder of this instruction two operands. The two defined strings are used to describe these two operands.

: "= m": The first colon is used to describe the "output" operand in the instruction. The ADDR in the scraping number connects the operands to the variable of the C language. This defined string represents "% 0" in the instruction is the memory operand pointing by the AddR pointer. This is a "output" type of memory operand.

: "IR" (NR): The second colon is defined after the colon is used to describe the "input" operand in the instruction. This defined string represents "% 1" in the instruction is the variable NR, which can be an immediate operand or a register operator.

* Note: The corresponding relationship between the defined string and the operand placeholder is: In all qualified strings (including all the first colon, all defined strings after the second colon), the first The string that appears is used to describe the operand "% 0", the second appearance string describes the number of operands "% 1", and so on. 1 Compilation instruction template in the assembly instruction template ASM statement is mainly composed of assembly instruction sequences and qualified strings. Multiple assembly instructions can be included in an ASM statement. Use an operand placeholder reference to the variables in the C language in the assembly instruction sequence. A maximum of ten operands can be included in an ASM statement:% 0,% 1, ...,% 9. The assembly instruction sequence is followed by the operand limit string, defining the placeholders in the instruction sequence. The defined content includes: which Coordel is corresponding to which C language variable, which can be the number of operands, and the like. Limited strings can be divided into three parts: output operand limit strings (defined strings after the first colon after the command sequence), enter the operand limit string (the first colon and the second column) There is also the third type of defined string after the second colon. The same type of defined string is separated between comma. The first qualified string that appears in the ASM statement is used to describe the placeholder "% 0", the second for describing the placeholder "% 1", so that the type of the defined string is pushed (regardless of the type of the defined string). If there is no output operand in the instruction sequence, then there should be two colons before the first qualified string (the string is used to describe the input operator), and the compiler knows that there is no output in the instruction. Operand).

The C language variable corresponding to the number of output operands in the command should have a left value, of course, there is no such left value limit for the output operand.

The output operand must be written, that is, the ASM is taken out of an operand, and then the result is saved back to the operand to save the operation. This type of assembly instruction is not straightforward, but must pass a specific Description of format. If the assembly instruction contains an operating number of an input-output type, then the two placeholders must be referenced in the template: one is responsible for input, the other is responsible for the output. E.g:

ASM ("AddL% 2,% 0": "= r" (foo): "0" (foo), "g"); "% 0" is an input in this instruction, "% 0" is an input - output The number of operands, "= R" (foo) is used to define its output function, the output result of the instruction is stored in the C language variable foo; there is no explicit "% 1" operand in the instruction, but for it There is a defined string "0" (foo), in fact the implicit "% 1" operand in the instruction is used to describe the input function of the "% 0" operand, and its "0" in the defined string is limited. "% 1" operands have the same address as "% 0". It can be understood that the template in the above instructions: This instruction adds the value in "% 1" and "% 2", and the calculation result is stored back "% 0", "% 1" and "% 0" in the instruction have The same address. Note that "0" defined characters used to describe "% 1" are sufficient to ensure that "% 1" has the same address as "% 0". However, if this input is completed with the following instructions - the output is not working properly:

ASM ("AddL% 2,% 0": "= r" (foo): "R" (foo), "G" (BAR)); although "% 0" and "% 1" are also referenced in this directive C Language Variable FOO, but GCC does not guarantee that they have the same address in the generated assembler.

There are also some compilation instructions that may change the value of certain registers, and this case must be notified in the compiler in the corresponding assembly instruction template. Therefore, there is a third type of defined string in the template, which follows the back of the input operand to define the string, between the colon intervals. These strings are the names of certain registers that represent the contents of these registers on behalf of the instruction. Some hardware registers may be directly referenced in the assembly instructions in an inline assembly instruction. We already know that in the assembly language of the AT & T format, the register name is prefixed as "%", in order to keep this "%" in the generated assembler, The reference to the hardware register must be used as the prefix of the register name in an ASM statement. If the assembly instruction changes the content of the hardware register, do not forget the notification compiler (add the corresponding string to the third type of qualified string). There are also instructions that may change the contents of the CPU flag register EFLAG, and the "CC" is added in the third type of qualified string.

In order to prevent GCC from changing assembly instructions in ASM during optimization, the "Volatile" modifier can be added after the "ASM" keyword.

Multi-assembly language instructions can be described in an ASM statement; use ";" or "/ n" between each assembly instruction.

2 Operation Limits Character Operation Limit Strings Describe the corresponding number of operands, some commonly used defined characters: (there are some limited characters involved, see gcc.info)

1. "m": The operand is the memory variable.

2. "o": The operand is a memory variable, but its addressing mode must be a "offset" type, that is, the base address or the base address address.

3. "V": The operand is a memory variable, its addressing method is not a "offset" type.

4. "": The operand is a memory variable, its address is automatically incremented.

6. "R": The operand is a general register.

7. "i": The operand is an immediate operand. (The value can be determined at the time of assembly)

8. "N": The operand is an immediate operand. Some systems do not support immediate operands other than words (double bytes), which are described in "N" instead of "i".

9. "g": The operand can be an immediate number, a memory variable, or a register, as long as the register belongs to a general purpose register.

10. "X": The operand allows for any type.

11. "0", "1", ..., "9": The operand is matched to a specified operand. That is, the operand is the specified number of operands. For example, if "0" is used to describe the "% 1" operand, then "% 1" reference is actually "% 0" operand.

12. "p": The operand is a legal memory address (pointer).

13. "=": The operand is only written (output operand) in the instruction.

14. " ": The number of operands is read in the instruction (input-output operand).

15. "a": register EAX.

16. "b": register EBX.

17. "c": register ECX.

18. "D": Register EDX.

19. "q": registers "a", "b", "c" or "d".

20. "A": register "a" or "d".

twenty one. "a": register EAX.

twenty two. "f": floating point number register.

twenty three. "T": The first floating point register. twenty four. "U": second floating point number register.

25. "D": Register DI.

26. "S": register Si.

27. The number of "i": 0-31 is the number of times. (For 32-bit shift instructions)

28. The number of "J": 0-63 is immediately. (For 64-bit shift instructions)

29. The number of "N": 0-255 is the number of immediate. (For "OUT" instructions)

30. "G": standard 80387 floating point constant.

* Note: There are still some uncommon qualifiers that are not hereby illustrated, and there are some qualified characters, such as "%", "&", etc., because I lack some knowledge in compiler, so I don't understand them. Meaning, if you have a master, you are willing to add, accidentally grateful! However, the definition characters that appear in the core code are almost these.

--ober 1999.3.31

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

New Post(0)