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.
By rosetta