asm 格式
示例
使用全局变量
/* golbaltest.c - An example of using C variables */
#include
int a = 10;
int b = 20;
int result;
int main()
{
asm( "pusha\n\t"
"movl a, %eax\n\t"
"movl b, %ebx\n\t"
"imull %ebx, %eax\n\t"
"movl %eax, result\n\t"
"popa");
printf("the answer is %d\n", result);
return 0;
}
约束码 | 描述 |
---|---|
a | 使用%eax %ax %al 寄存器 |
b | 使用%ebx %bx %bl 寄存器 |
c | 使用%ecx %cx %cl 寄存器 |
d | 使用%edx %dx %dl 寄存器 |
S | 使用%esi %si寄存器 |
D | 使用%edi %di 寄存器 |
r | 使用任意寄存器 |
q | 使用%eax %ebx %ecx %edx中任意寄存器 |
A | 使用%eax和%edx存储64位数据 |
f | 使用浮点数寄存器 |
t | 使用浮点数寄存器的栈顶 |
u | 使用浮点数寄存器的第二个 |
m | 使用变量的内存位置 |
o | 使用一个内存偏移 |
V | 使用一个直接的内存地址 |
i | 使用立即数 |
n | 使用一个已赋值的立即数 |
g | 使用寄存器或内存变量 |
输出描述符 | 描述 |
---|---|
+ | 同时可以读取和写入的操作 |
= | 只可以写入的操作 |
% | 可以和下一个操作互换 |
& | 可以被删除和重复使用的操作 |
asm("assembly code" : "=a"(result) : "d"(data1), "c"(data2));
说明: 将c语言变量data1写入%edx, data2写入%ecx,result写入%eax
/* regtest.c - An example of using registers */
#include
int main()
{
int data1 = 10;
int data2 = 20;
int result ;
asm("imull %%edx, %ecx\n\t"
"movl %%ecx, %eax"
: "=a"(result)
: "d"(data1), "c"(data2));
printf("The result is %d\n", result);
return 0;
}
/* movstest.s - An example of instructions with only input values */
#include
int main()
{
char input[30] = {"This is a test message.\n"}
char output[30];
int length = 25;
asm volatile("cld\n\t"
"rep movsb"
:
: "S"(intput), "D"(output), "c"(length));
printf("%s", output);
return 0;
}
注: 因为没有定义输出,需要设置“volatile",防止编译器优化掉asm段
asm("assembly code"
: "=r"(result)
: "r"(data1), "r"(data2));
%0 代表存储result的寄存器
%1 代表存储data1的寄存器
%2 代表存储data2的寄存器
/* regtest.s - An example of using placeholders */
#include
int main()
{
int data1 = 10;
int data2 = 20;
int result;
asm("imull %1, %2\n\t"
"movl %2, %0"
: "=r"(result)
: "r"(data1), "r"(data2));
printf("The result is %d\n", result);
return 0;
}
asm ( "imull %1, %0"
: ”=r"(data2)
: "r"(data1), "0"(data2));
0 标识使用第一个参数的寄存器
/* regtest.c - An example of using placeholders for a common value */
#include
int main()
{
int data1 = 10;
int data2 = 20;
asm ("imull %1, %0"
: "=r"(data2)
: "r"(data1), "0"(data2));
printf("The result is %d\n", data2);
return 0;
}
asm ("imull %[value1], %[value2]"
: [value2] "=r"(data2)
: [value1] "r"(data1), "0"(data2));
value1, value2 代表data1、data2所在寄存器的别名
/* alttest.c - An example of using alternative placeholders */
#include
int main()
{
int data1 = 10;
int data2 = 20;
asm ("imull %[value1], %[value2]"
: [value2] "=r"(data2)
: [value1] "r"(data1), "0"(data2));
printf("The result is %d\n", data2);
return 0;
为了指出哪些不在输入输出中使用的额外的寄存器
/* changetest.c - An example of setting register in the changed registers list */
#include
int main()
{
int data1 = 10;
int result = 20;
asm ("movl %1, %%eax\n\t"
"addl %%eax, %0"
: "=r"(result)
" "r"(data1), "0"(result)
: %eax");
printf("The result is %d\n", result);
return 0;
}
使用m 限定符来使用c语言中的变量地址
/* memtest.c - An example of using memory locations as values */
#include
int main()
{
int dividend = 20;
int divisor = 5;
int result;
asm("divb %2\n\t"
"movl %%eax, %0"
: "=m"(result)
: "a"(dividend), "m"(divisor));
printf("The result is %d\n", result);
return 0;
}
f 代表可使用的浮点数寄存器
t 代表浮点数寄存器的栈顶
u 代表浮点数寄存器的二层栈
如果需要从浮点数栈中获得元素,需要使用t或u定位符
asm ( "fsincos"
: "=t"(cosine), "=u"(sine)
: "0"(radian));
fsincos 指令将输出存放在栈顶的两个寄存器
/* sincostest.c - An example of using two FPU registers"
#include
int main()
{
float angle = 90;
float radian, cosine, sine;
radian = angle / 180 * 3.14159;
asm ( "fsincos"
: "=t"(cosine), "=u"(sine)
: "0"(radian));
printf("The cosine is %f, and sine if %f\n", cosine, sine);
return 0;
}
/* areatest.c - An example of using floating point regs */
#include
int main()
{
int radius = 10;
float area;
asm("fild %1\n\t"
"fimul %1\n\t"
"fldpi \n\t"
"fmul %%st(1), %%st(0)"
: "=t"(area)
: "m"(radius)
: "%st(1)");
printf("The result is %f\n", area);
return 0;
}
/* jmptest.c - An example of using jumps in inline assembly */
#include
int main()
{
int a = 10;
int b = 20;
int result;
asm("cmp %1, %2\n\t"
"jge greater\n\t"
"movl %1, %0\n\t"
"jmp end\n"
"greater:\n\t"
"movl %2, %0\n"
"end:"
: "=r"(result)
: "r"(a), "r"(b));
printf("The larger value is %d\n", result);
return 0;
}
为了解决跳转中标签重定义的问题,我们使用内部标签,并使用f标识向前寻找,b标识向后寻找
/* jmptest.c - An example of using generic jumps in inline assembly */
#include
int main()
{
int a = 10;
int b = 20;
int result;
asm("cmp %1, %2\n\t"
"jge 0f\n\t"
"movl %1, %0\n\t"
"jmp 1f\n"
"0: \n\t"
"movl %2, %0\n"
"1:"
: "=r"(result)
: "r"(a), "r"(b));
printf("The larger value is %d\n", result);
return 0;
}
内嵌汇编一般使用宏定义的方式
/* mactest.c - An example of using inline assembly macros in a program */
#include
#define GREATER(a, b, result) ({\
asm("cmp %1, %2\n\t" \
"jge 0f\n\t" \
"movl %1, %0\n\t" \
"jmp 1f\n\t" \
"0:\n\t" \
"movl %2, %0\n\t" \
"1:"\
: "=r"(result) \
: "r"(a), "r"(b)); })
int main()
{
int data1 = 10;
int data2 = 20;
int result;
GREATER(data1, data2, result);
print("a = %d, b = %d result : %d\n", data1, data2, result);
data1 = 30;
GREATER(data1, data2, result);
print("a = %d, b = %d result : %d\n", data1, data2, result);
return 0;
}