Copyleft of this document belongs to Rosetta and can be freely copied and reproduced when published using GPL. ensure the integrity of the document during reprinting.
References: Linux kernel full analysis, new assembly language programming, and Linux C Programming one-stop learning
Recently, a key part of the C language algorithm needs to be implemented in assembly language. In Linux, at&t assembly is basically used for Embedded Assembly. For example, at&t assembly is used for Linux system startup. I have studied at&t assembly before, but I have forgotten it after a while, but I am familiar with Intel assembly basics. The two are basically similar in usage, so I am familiar with Intel assembly, it's easy to spend some time reading at&t's compilation.
Next, let's take a look at the differences between the two and give a specific example of embedding at&t assembly in the Linux language.
I. Differences between at&t assembly and Intel assembly
1. The order of source and destination operands is the opposite. The source and purpose of at&t are from left to right, and "%" must be added before its register; intel is from right to left, and "%" is not required ".
Example: at&t: movl % ECx, % eax (ECx is the source operand, eax is the destination operand)
Intel: mov dx, Bx (BX is the source operand, dx is the destination operand
2. at&t needs to add "$" before the immediate operand; Intel does not need it.
Example: at&t: movl $2, % eax
Intel: mov ax, 2
3. The length of memory operations in at&t is determined by the last character of the operating code. "B", "W", "L", respectively, indicates that the memory reference is 1-byte 8-bit, 2-byte 16-bit, and 4-byte 32-bit.
Intel uses the operation prefix byte PTR, word PTR, and dword ptr.
Example: at&t: movl % ECx, % eax
Intel: mov Al, byte PTR ttt
These three points are the most important differences. In addition, the jump/call time is not the same.
Ii. Embedded Assembly basic format
ASM ("Assembly Statement"
"Output register"
"Input register"
"The modified register" // tells the compiler that the specified register must be rewritten when the _ ASM _ statement is executed, therefore, do not use the register here to save other values during this period.
)
// ASM. c
# Include <stdio. h>
Unsigned int leftshift (unsigned int uinumber, unsigned char ibits)
{
Register unsigned int _ res;
_ ASM _ ("Rol % 1, % eax ;"
: "= A" (_ res)
: "C" (ibits), "0" (uinumber)
);
Return _ res;
}
Int main (void)
{
Unsigned int ret = 0;
Ret = leftshift (4, 2 );
Printf ("1, RET: % u \ n", RET );
Return 0;
}
[Root @ xxx asm_study] # gcc asm. C-o app
[Root @ xxx asm_study] #./APP
1, RET: 16
The preceding example shows the Left shift of a loop. Instead of focusing on the Left shift of the loop, it refers to the ROL itself and only the at&t Assembly usage.
First, a register Variable _ RES is defined to save the return value.
At&t Assembly uses registers, which must be preceded by "%". In C, "%" is a special format character, therefore, two percent signs "%" are required to finally represent a "%", which is a bit similar to the escape character.
: "= A" (_ res) indicates that the value of register eax is output to _ res, and % 0 indicates this register,
: "C" (ibits), "0" (uinumber), C indicates the input sender ECx, 0 indicates that the above output register eax is used, therefore, ECx and eax respectively Save the ibits and uinumber variable values. In the instruction, % 1 refers to the Register ECx, so its numbering rules start from "output sender" from left to right, from top to bottom.
It can be found that ROL % 1, % eax can be directly written as: ROL % 1, % 0
C language version shifts left
A c language version is provided to move the code left by loop. If you are interested, you can compare it with the assembly version above.
// Ori. c
Unsigned int leftshift2 (unsigned int uinumber, unsigned char ibits)
{
Int I = 0;
Unsigned int iret = uinumber;
Unsigned int IR = 0x01;
For (I = 0; I <ibits; I ++)
{
IR = iret & 0x80000000;
Iret = iret <1;
IR = IR> 31;
Iret = iret | IR;
}
Return iret;
}
Int main (void)
{
Unsigned int ret = 0;
Ret = leftshift2 (4, 2 );
Printf ("2, RET: % u \ n", RET );
Return 0;
}
[Root @ xxx asm_study] # GCC Ori. C-o app
[Root @ xxx asm_study] #./APP
2, RET: 16
Iv. macro definition version Compilation
# Define leftshift (uinumber, ibits )\
({\
Register unsigned int _ res ;\
_ ASM _ ("Rol % Cl, % eax ;"\
: "= A" (_ res )\
: "C" (ibits), "a" (uinumber ));\
_ Res ;})
The difference from a normal assembly is that "\" must be added after each line, and the return value is written to the end, as shown in the last _ res above.
V. C program is transformed into assembler program
1. Convert *. C program into at&t format Assembly *. s
[Root @ xxx asm_study] # gcc-s ASM. C-o ASM. s
[Root @ xxx asm_study] # ls-Al ASM. s
-RW-r -- 1 Root 1387 06-30 10:41 ASM. s
2. Convert *. C program into Intel format Assembly *. s
[Root @ xxx asm_study] # gcc-MASM = intel test. C-O test. s
Of course, if you want to convert a C program into an Intel assembly, it cannot contain an assembly in at&t format; otherwise, it cannot be transferred.