Best x GCC inline assembly

Source: Internet
Author: User

Best x GCC inline assembly
GuideAs you know, inserting the assembly language into the C language is the basic assembly program syntax used in Linux. This article describes the usage and usage of the inline assembly feature provided by GCC. There are only two prerequisites for reading this article. Obviously, it is the basic understanding of x86 assembly language and C language.1. Introduction1.1 copyright permit

Copyright (C) 2003 Sandeep S.

This document is free to share; you can re-release it and/or modify it under the GNU General Public License issued by the Free Software Foundation; it can also be version 2 of the license or a later version (as required.

The release of this document is intended to help others, but does not have any warranties; it does not include sales or warranties applicable to any specific purpose. For more information, see the GNU General License.

1.2 feedback correction

Submit the feedback and criticism to Sandeep. S. I would like to thank anyone who points out the errors and inaccuracies in this document. Once notified, I will immediately correct them.

1.3 thanks

I would like to express my sincere gratitude to the GNU people who provide such great features. Thanks to Mr. Pramode c e for all the help. I would like to thank my friends at Govt Engineering College and Trichur for their spiritual support and cooperation, especially Nisha Kurur and Sakeeb S. Thank you for your cooperation with the teachers at Gvot Engineering College and Trichur.

In addition, thanks to Phillip, Brennan Underwood and colin@nyx.net, many of the items here are taken straight from their work.

2. Overview

Here, we will learn about GCC inline assembly. What does inline represent here?

We can ask the compiler to insert the code of a function into the caller's code where the function is actually called. Such a function is an inline function. Which sounds like a macro? The two are indeed similar.

What are the advantages of inline functions?

This inline method can reduce the overhead of function calls. At the same time, if the values of all real parameters are constants, their known values can be simplified during compilation, so not all inline function code needs to be included. The impact of code size is unpredictable, depending on the specific situation. To declare an inline function, we must use the "inline" keyword in the function declaration.

Now we are at a point where we guess exactly what inline assembly is. It is just an assembly program written as an inline function. They are convenient, fast, and extremely useful in system programming. We mainly focus on the basic formats and usage of (GCC) inline assembler functions. To declare inline assembler functions, we use the "asm" keyword.

Inline assembly is important mainly because it can operate and display its output through the C variable. Because of this capability, "asm" can be used as an interface between assembly instructions and C Programs that contain it.

3. GCC Assembly syntax

The gnu c compiler GCC on Linux, usingAT&T/UNIX Assembly syntax. Here, we will use AT&T syntax for assembly encoding. If you are not familiar with AT&T syntax, don't be nervous. I will teach you. AT&T syntax differs greatly from Intel syntax. I will give the main difference.

1. Source and Destination operands

The direction of AT&T's syntax is exactly the opposite of Intel's syntax. In Intel syntax, the first operand is the destination operand, and the second operand is the source operand. However, in AT&T syntax, the first operand is the source operand, and the second operand is the destination operand. That is to say,

The "Op-code dst src" in Intel syntax is changed to "Op-code src dst" in AT&T syntax ".

2. Register name

The register name has a prefix of "%", that is, if you must use "eax", it should be used as "% eax ".

3. Immediate count

AT&T immediately counts "$" as the prefix. Static "C" variables also use the "$" prefix. In Intel syntax, hexadecimal constants are suffixed with "h". However, AT&T does not use this syntax. Here we add the prefix "0x" to constants ". Therefore, for the hexadecimal system, we first see a "$", then "0x", and finally a constant.

4. operand size

In AT&T syntax, the size of the memory operand depends on the last character of the operating code name. The operation code suffixes 'B', 'w', and 'l' indicate the byte (8 bits), word (16 bits), and long (32 bits) memory references respectively. Intel syntax adds "byte ptr", "word ptr", and "dword ptr" prefixes to memory operations to achieve this function.

Therefore, Intel's "mov al, byte ptr foo" is "movb foo, % al" in AT&T syntax ".

5. Memory operations

In Intel syntax, base address registers are included in "[" and "]", but in AT&T, they are changed to "(" and ")". In Intel syntax, the indirect memory reference is

"Section: [base + index * scale + disp]", which is changed to "section: disp (base, index, scale)" In AT&T )".

Note that when a constant is used for disp or scale, the "$" prefix cannot be added.

Now we see some major differences between Intel syntax and AT&T syntax. I only wrote a part of their differences. For more information, see the GNU compilation documentation. For better understanding, we can look at some examples.

+------------------------------+------------------------------------+|       Intel Code             |      AT&T Code                     |+------------------------------+------------------------------------+| mov     eax,1                |  movl    $1,%eax                   |   | mov     ebx,0ffh             |  movl    $0xff,%ebx                |   | int     80h                  |  int     $0x80                     |   | mov     ebx, eax             |  movl    %eax, %ebx                || mov     eax,[ecx]            |  movl    (%ecx),%eax               || mov     eax,[ebx+3]          |  movl    3(%ebx),%eax              | | mov     eax,[ebx+20h]        |  movl    0x20(%ebx),%eax           || add     eax,[ebx+ecx*2h]     |  addl    (%ebx,%ecx,0x2),%eax      || lea     eax,[ebx+ecx]        |  leal    (%ebx,%ecx),%eax          || sub     eax,[ebx+ecx*4h-20h] |  subl    -0x20(%ebx,%ecx,0x4),%eax |+------------------------------+------------------------------------+
4. Basic inline

The format of basic inline assembly is very straightforward. Its basic format is:
Asm ("assembly code ");
Example

Asm ("movl % ecx % eax");/* move the ecx register content to eax */_ asm _ ("movb % bh (% eax )"); /* move a byte of bh data to the memory pointed to by the eax register */

You may have noticed that "asm" and "_ asm _" are used here __". Both are valid. If the keyword "asm" conflicts with some identifiers of our program, we can use "_ asm __". If we have more than one instruction, we can enclose each line with double quotation marks and add the suffixes '/N' and'/t' for each instruction. This is because gcc sends each line to the as (GAS) (LCTT: GAS (GNU Assembler) as a string, and sends the lines correctly formatted to the assembler by using line breaks/tabs.

Example

__asm__ ("movl %eax, %ebx/n/t"         "movl $56, %esi/n/t"         "movl %ecx, $label(%edx,%ebx,$4)/n/t"         "movb %ah, (%ebx)");

If some registers are involved in the Code (that is, the content of the changes), but the changes are returned from the Assembly without restoring them, this will lead to some unexpected things. This is because GCC does not know the changes in the register content, which can cause problems, especially when the compiler performs some optimizations. Without notifying GCC, it will assume that some registers store some values -- and we may have changed but didn't tell GCC -- it will continue to run like nothing happens: nothing happened. It means that GCC will not assume that the value loaded into the register is valid. After exiting the inline assembly that changes the register value, the register value is not saved to the corresponding variable or memory space ). What we can do is to use commands without any side effects, or restore these registers when we exit, or wait for the program to crash. This is why we need some extended functions. The extended compilation provides us with those features.

5. Extended Assembly

In basic inline assembly, we only have commands. However, in the Extended Assembly, we can specify the operands at the same time. It allows us to specify the input registers, output registers, and modify the register list. GCC does not force users to specify the registers used. We can leave the headache to GCC, which may better adapt to GCC optimization. In any case, the basic format is:
Asm (assembler Template
: Output operand/* optional */
: Input operand/* optional */
: Modify the register list/* optional */
);

The assembler template consists of Assembly commands. Each operand is described by an operand constraint string followed by a C expression enclosed by an arc. The colon is used to separate the assembler template from the first output operand, and the other (colon) is used to separate the last output operand from the first input operand (if any ). Commas are used to separate the operands in each group. The total number of operands is limited to 10, or the maximum number of operands in any instruction format in the machine description, whichever is greater.

If there is no output operand but there is an input operand, You must place two consecutive colons around the place where the output operand would have been originally placed.

Example:

Asm ("cld/n/t" "rep/n/t" "stosl":/* No output register */: "c" (count ), "a" (fill_value), "D" (dest): "% ecx", "% edi ");

Now let's take a look at what this code is doing? The above inline assembly copies the "fill_value" value "count" times to the position indicated by the Register "edi, the value of the Register edi increases or decreases depending on whether the ction flag is set. Therefore, the above Code initializes a memory block ). It also tells the gcc registers "ecx" and "edi" that they are always invalid. For more clarity, let's look at another example.

Int a = 10, B; asm ("movl % 1, % eax; movl % eax, % 0;": "= r" (B) /* output */: "r" (a)/* input */: "% eax"/* modify register */);

What we do here is to use the Assembly command to make the value of the 'B' variable equal to the value of the 'A' variable. Some interesting points are:

  1. "B" is the output operand, referenced with % 0, and "a" is the input operand, referenced with % 1.
  2. "R" is the operand constraint. Then we will learn more about constraints (strings ). Currently, "r" tells GCC to store operands using any register. The output operand constraint must have a constraint modifier "= ". This modifier indicates that it is a read-only output operand.
  3. Register names are prefixed with two %. This helps GCC distinguish between operands and registers. The operation count is prefixed with %.
  4. The modifier register % eax after the third colon is used to tell GCC % eax that the value will be modified inside "asm", so GCC will not use this register to store any other value.

After "asm" is executed, the "B" variable maps to the updated value because it is specified as the output operand. In other words, changes to the "B" variable in "asm" should be mapped to the "asm" external.

Now, we can look at each domain in more detail.

1. assembler Template

The assembler template contains the assembly instruction sets inserted into the C program. The format is as follows: each instruction is circled with double quotation marks, or the entire instruction group is circled with double quotation marks. At the same time, each command should end with a separator. Valid delimiters include line breaks ("/n") and semicolons (";"). "/N" can be followed by a tab ("/t "). Should we all understand why line breaks or tabs are used )? The operands corresponding to the C expression are represented by % 0, % 1... and so on.

2. operands

The C expression is used as the number of assembler commands in "asm. Each operand is subject to an operand enclosed by double quotation marks. There is also a constraint modifier in the quotation marks for the output operands, followed by a C expression used to represent the operands. That is, the "operand constraint" (C expression) is a common format. There is an additional modifier for the output operand. The constraint string is mainly used to determine the addressing method of the operands and also to specify the registers used.

If we use more than one operand, each operand is separated by a comma.

In the assembler template, each operand is referenced by a number. The numbering method is as follows. If there are n operands (including input and output operands) in total, the first output operand number is 0, increasing one by one, and the last input operand number is n-1. The maximum number of operands is described in the previous section.

The output operand expression must be a left value. The requirements for input operands are not as strict as they are. They can be expressions. Extended Assembly features are often used for machine commands not known to the compiler ;-). If the output expression cannot be directly addressable (that is, it is a single-bit field), Our constraint string must be given a register. In this case, GCC will use this register as the output of the Assembly, and then store the content of this register to the output.

As stated above, normal output operations must be written only. GCC assumes that the Operation values before the command are dead and do not need to be generated (in advance. Extended Assembly also supports input-output or read-write operations.

So now let's take a look at some examples. We want to request a result of the fifth power of a number. To calculate this value, we use the "lea" command.

asm ("leal (%1,%1,4), %0"     : "=r" (five_times_x)     : "r" (x)      );

Here we enter x. We do not specify the registers used. GCC will select some input registers and one output register for our expected work. If we want to put the input and output in the same register, we can also require GCC to do this. Here we use the read-write operand types. Here we can implement it by specifying the appropriate constraints.

asm ("leal (%0,%0,4), %0"     : "=r" (five_times_x)     : "0" (x)      );

The output and output operations are in the same register. However, we cannot know which register is used. Now, if we want to specify the register where the operand is located, here is a method.

asm ("leal (%%ecx,%%ecx,4), %%ecx"     : "=c" (x)     : "c" (x)      );

In the above three examples, we have not added any registers to the modifier register list. Why? In the first two examples, GCC determines the register and it knows what has changed. In the last example, we do not need to add 'ecx' to the modifier register list (LCTT: The word spelling in the source modifier register list is incorrect, which has been corrected here). gcc knows that it represents x. Therefore, because it can know the value of "ecx", it will not be regarded as a modifier (register.

3. Modify the register list

Some commands may corrupt some hardware register content. We have to list these registers in the modifier register, that is, the third in the assembler function'. This notifies gcc that we will use and modify these registers by ourselves, so that gcc will not assume that the values stored in these registers are valid. We do not need to list the input and output registers in this list. Because gcc knows that "asm" uses them (because they are explicitly specified as constraints ). If the instruction uses any other register implicitly or explicitly (and the Register does not appear in the output or output Constraints List), you need to specify these registers in the modifier register list.

If our command can modify the condition code register (cc), we must add "cc" to the modification register list.

If our commands modify the memory in an unpredictable way, you need to add "memory" to the modified register list. This prevents GCC from keeping the memory value cached in the register between Assembly commands. If the affected memory is not in the input or output list of the Assembly, you must add the "volatile" keyword.

We can read and write modifier registers multiple times as needed. Refer to the multi-instruction example in the template. It assumes that the subroutine _ foo accepts the parameters in registers "eax" and "ecx.

asm ("movl %0,%%eax;      movl %1,%%ecx;      call _foo"     : /* no outputs */     : "g" (from), "g" (to)     : "eax", "ecx"     );
4. Volatile ...?

If you are familiar with the kernel source code or similar beautiful code, you must have seen many functions declared as "volatile" or "_ volatile, it is followed by an "asm" or "_ asm __". I have mentioned the keywords "asm" and "_ asm __". So what is volatile?

If our Assembly statement must be executed where we place it (for example, it cannot be removed from the loop statement for optimization), place the keyword "volatile" behind asm ,(). To prevent it from being moved, deleted, or otherwise, we declare it as "asm volatile (...:...:...:...);"

If you are worried about a conflict, use "_ volatile __".

If our compilation is only used for some calculations and has no side effects, it would be better not to use the "volatile" keyword. Without "volatile", gcc can optimize the code and make the code more beautiful.

In the "Some Practical Tips" section, I provide examples of multiple inline assembler functions. We can see the details of the modified register list.

6.

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.