Skip to content

Latest commit

 

History

History
196 lines (145 loc) · 6.46 KB

7.Extended_Asm.adoc

File metadata and controls

196 lines (145 loc) · 6.46 KB

CHAPTER 7. Inline Assembly

The asm keyword allows you to embed assembler instructions within C code. The compiler provides two forms of inline assembly statements: basic assembly statements, which have no operands, and extended assembly statements, which include one or more operands to interact with C variables.

In the process of program development, assembly language can achieve functionalities that cannot be accomplished by C language in certain situations, which requires the use of extended asm.

7.1 Basic Assembly

Refer to the "Instruction Set" section in the Programming Manual document for details on all instructions.

Here is an example:

Inline assembly code is used to write pure assembly code in a C/C++ program:

int main()
{
    asm volatile("move $r23, $r24");
    asm volatile("addi.w $r23, $r24, 1");
}

Use the following format in the block of instructions, noting that \n\t should be included at the end of each instruction:

int main()
{
    asm volatile("move $r23, $r24\n\t"
                 "addi.w $r23, $r24, 1\n\t");
}

Usage :

We will write a simple code to:

  • Load values from two addresses: 0x20001000 and 0x20001004

  • Store the sum of these values at a new address: 0x20001008

int main(void) {
  __asm volatile(
    "ld.d  $r23, $r0,  0x120001000\n\t"
    "ld.d  $r24, $r0,  0x120001004\n\t"
    "add.d $r25, $r23, $r24\n\t"
    "st.d  $r25, $r0,  0x120001008\n\t");
}

7.2 Extended Assembly

The full syntax of Inline Assembly is:

asm volatile ( AssemblerTemplate
             : OutputOperands
             : InputOperands
             : Clobbers )
asm goto(AssemblerTemplate
       : OutputOperands
       : InputOperands
       : Clobbers
       : GotoLabels)

AssemblerTemplate :

  • This is a literal string that is the template for the assembler code. It is a combination of fixed text and tokens that refer to the input, output, and goto parameters.

asm volatile("move $r23, $r24"); // is the same as
asm volatile("move $r23, $r24":::);

OutputOperands :

  • A comma-separated list of C variables modified by the instructions in the Assembler Template. An empty list is permitted.

Here is an example:

int result;
int d1, d2;
... ...
asm volatile("add.w %0 , %1 , %2 \n\t"
           : "=r" (result)
           : "r" (d1), "r" (d2):);

In the above example, the instructions and operands used by extended asm are first described. The ':' character informs the compiler aboout the meaning of this assembly instruction and the number of operands required. The constraints '=r' and 'r' indicate that these are register operands, with 'r' representing a fixed-point register operand and '=' indicating an output operand. In constrast, if there is no =, it represents an input operand. With this information, the compiler can understand how to convert the extended asm into actual assembly instructions.

If the extended asm is bound to a register variable, it’s important to note that if the extended asm uses a temporary register to store the result, or if a register variable is bound to a temporary register, that value may change during the function call. This is because the value of the temporary register will not be maintained by the system during the function call, so manual instructions need to be added for maintenance. Therefor, it is recommended to use saved registers as much as possible in extended asm.

InputOperands :

  • A comma-separated list of C expressions read by the instructions in the AssemblerTemplate. An empty list is permitted.

  • Sometimes we need to use designated registers in assembly instructions. A typical example is a system call, where the system call number and parameters must be placed in specific designated registers.

  • To achieve this goal, we need to use extended syntax when declaring variables.

Here is an example:

register int a asm("$a0") = 1;
register int b asm("$a1") = 2;

asm volatile("addi.w %0,%1,0xf\n\t"
              :"=r"(a)
              :"r"(b));

If the registers used in extended assembly are specified in the instruction description, it should be noted that general-purpose registers can be represented as either $GR or GR; the '$' symbol is not necessary. However, floating-point registers must contain the '$' symbol and must be represented as $FR. Please do not use its alias for FR .

Clobbers :

  • A comma-separated list of registers or other values changed by the AssemblerTemplate, beyond those listed as outputs. An empty list is permitted.

  • Some assembly instructions may implicitly modify some registers that are not in the instruction operand. In order to make the compiler aware of this situation, the rules for implicit register changes are listed after the input rules.

Here is an example:

asm volatile("xor $r25, $r25, %0\n\t"
            ::"r"(a):"r25");

GotoLabels :

With extended asm, you can read and write C variables from assembler and perform jumps from assembler code to C labels. The extended asm syntax uses colons (':') to delimit the operand parameters after the assembler template:

asm goto( AssemblerTemplate
        : OutputOperands
        : InputOperands
        : Clobbers
        : GotoLabels)

Here is an example:

    ra = 0;
    asm goto("beqz  %0, %l[labelbeqz] \n\t"
             :
             :"r"(ra):
             :labelbeqz);
    // code
labelbeqz:
    // code

"%l[labelbeqz]" indicates the target label to jump to in the C language source code, while embedding the assembly in the format of "goto":

This is useful for above cases:

  • Move the content of a C variable to a LoongArch register.

  • Move the content of a LoongArch register to a C variable.

  • Access assembly instructions that are not readily available in C programs.

For more content related to extended asm, please refer to: