Some information in GCC embedded assembly

  
 

Inline assembly, you can specify a C language expression as the operand of an assembly instruction, and you don't have to worry about how to read the value of a C language expression into which register, and how to write the result back to the C variable. You only need to tell the correspondence between the C language expression and the assembly instruction operand in the program, GCC will automatically insert the code to complete the necessary operations.

1. Simple inline assembly Example: __asm__ __volatile__("hlt"); “__asm__” indicates that the following code is inline assembly, “asm” is an alias for “__asm__”. “__volatile__” indicates that the compiler does not optimize the code, the following instructions remain as they are, "volatile" is its alias. Inside the brackets is the assembly instruction. In inline assembly, you can specify the C language expression as the operand of the assembly instruction, and you don't have to worry about how to read the value of the C language expression into which register, and how to write the result back to the C variable, you just tell The correspondence between the C language expression and the assembly instruction operand in the program can be, GCC will automatically insert the code to complete the necessary operations.

1. Simple inline assembly Example: __asm__ __volatile__("hlt"); “__asm__” indicates that the following code is inline assembly, “asm” is an alias for “__asm__”. “__volatile__” indicates that the compiler does not optimize the code, the following instructions remain as they are, "volatile" is its alias. Inside the brackets is the assembly instruction.

2. Inline assembly example To use inline assembly, you must first write an assembly instruction template, then associate the C language expression with the operand of the instruction, and tell GCC what restrictions are imposed 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” represents the operands of the instruction, called placeholders, by which the inline assembly corresponds to the C language expression and the instruction operand. The instruction template is enclosed in parentheses in C language expressions. In this case, there are only two: “result” and “input”, they are in the order of appearance and instruction operands “%0”,” %1” Correspondence; note the corresponding order: the first C expression corresponds to “%0”; the second expression corresponds to “%1”, and so on, there are at most 10 operands, respectively, using “%0&rdquo ;,“%1”….“%9” In front of each operand is a string enclosed in quotation marks. The content of the string is a restriction or requirement for the operand. “result” The preceding limit string is “=r”, where “=” indicates that <;result” is the output operand, “r” indicates that <;result" needs to be associated with a general purpose register First, the value of the operand is read into the register, and then the corresponding register is used in the instruction, instead of "result", of course, after the instruction is executed, the value in the register needs to be stored in the variable "result", from the surface It seems that the instruction directly operates on “result”, in fact, GCC does implicit processing, so that we can write less instructions. “input” The preceding “r” indicates that the expression needs to be put into a register first, and then used in the instruction to participate in the operation. The relationship between C expressions or variables and registers is handled automatically by GCC. We only need to use a restricted string to guide GCC on how to handle it. The limit character must match the instruction's operand requirement, otherwise the generated assembly code will be wrong. The reader can change both of the above examples to "ld"; m” (m means the operand is placed In memory, not in registers, the result of compiling is: movl input, result It is obvious that this is an illegal instruction, so the limit string must match the instruction's operand requirement. For example, the instruction movl allows registers to registers, immediately counts to registers, etc., but does not allow memory-to-memory operations, so two operands cannot use “m” as a qualifier. The inline assembly syntax is as follows: __asm__ (assembly statement template: output part: input part: destruction description part) There are four parts: assembly statement template, output part, input part, destruction description part, each part uses “:” Open, assembly statement template is essential, the other three parts are optional, if the latter part is used, and the front part is empty, you also need to use “:” grid, the corresponding part is empty. For example: __asm__ __volatile__("cli": : :"memory")

1. Assembly statement template The assembly statement template consists of a sequence of assembly statements, using “;”,“\\ n” or “\ \\t” separate. The operands in the instruction can use a placeholder to reference a C language variable with up to 10 operand placeholders with the following names: %0, %1, …, %9. The operands represented by placeholders in instructions are always treated as long (4 bytes), but the operations applied to them can be words or bytes depending on the instruction, when the operand is treated as a word or byte. When, the default is low word or low byte. The byte operation can be explicitly indicated whether it is a low byte or a minor byte. The method is to insert a letter between the % and the serial number, “b” represents the low byte, “h” represents the high byte, for example: %h1.

2. Output section The output section describes the output operand. The different operand descriptors are separated by commas. Each operand descriptor consists of a qualified string and a C language variable. The qualified string for 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 constraint on the variable, so that GCC can decide how to allocate the register based on these conditions. Generates the necessary code to handle the connection between the instruction operand and the C or C variable.

3, the input part of the input part describes the input operand, the different operand descriptors are separated by commas, each operand descriptor consists of a qualified 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 latter function sets 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: btsl nr, ADDR, the two operands of the instruction cannot be all memory variables, so the nr qualified string is specified as "Ir"; nr and immediately The number or register is associated such that only ADDR of the two operands is a memory variable.

Copyright © Windows knowledge All Rights Reserved