AT&T内嵌汇编的格式

文章目录

  • 一般的内嵌汇编
  • 扩展内嵌汇编
  • 内嵌汇编的使用

一般的内嵌汇编

  • asm 格式

    • asm(“assembly code”);
  • 示例

    • asm(“movl $1, %eax\n\tmovl $0, %ebx\n\tint $0x80”);
    • asm( “movl $1, %eax\n\t”
      “movl $0, %ebx\n\t”
      “int $0x80”);
  • 使用全局变量

/* 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;
}
  • 使用volatile关键字
    • asm volatile (“assembly code”)
  • 使用别名
    asm

扩展内嵌汇编

  • 扩展asm格式
    • asm(“assembly code” : output localtion : input operands : changed registers);
  • 指定输入输出
    • 格式
      “constraint”(variable)
    • 说明
      constraint 指定变量的存放位置
    • 约束码说明
约束码 描述
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;
}

你可能感兴趣的:(汇编)