C语言内联AT&T汇编概要
1 AT&T 语法概要
1.1 寄存器
8位: %ah %al
16位:%ax
32位:%eax
64位:%rax
1.2 操作符
8位: b
16位:w
32位:l
64位:q
1.3 操作数方向
源 -> 目的
1.4 立即数
$64
1.5 内存引用
Intel格式:section:[base+index*scale+displacement]
e.g:mov [ebp+eax*2-0x10], 0x41
AT&T: section:displacement(base,index,scale)
e.g:movb $0x41, -0x10(%ebp,%eax,2)
2 内联格式
-
__asm__ __volatile__ (
-
"movl $1, %%eax ;\n"
-
: output
-
: imput
-
: modify
-
);
2.1 __volatile__ 不解释。
2.2 每句汇编在
" " 以内,且以
;\n 结束。
2.3 在内联格式中,寄存器要写为%%rax %%eax格式;%0 %1为占位符使用。
2.4 output/imput 关联到 C 变量/常量。
2.5 modify 向编译器指明不需要优化的部份,如 "memory" "ax" "bx"。
3 output/imput 的详细分析
output/imput 可以理解为与C语言的接口,几乎所有的内联都会用到这两个域,所以本文会详细描述这两者的区别。
3.1 一个内联的例程
-
void example( )
-
{
-
char c = 'a';
-
-
__asm__ __volatile__ (
-
"movb $84, %0 ; \n"
-
: "=r" (c) //output
-
: //input
-
: "memory"
-
);
-
-
printf("[%c]\n", c);
-
}
3.2 常用操作约束
在上面例子中的output域引号中的内容,就是“操作约束”(
Operation Constraint);操作约束后括号内,就是C语言的变量或者常量。
操作约束分为两部分:操作约束 "=" 和 存储约束 "r" 。
操作约束:“=” Write-Only
“+” Read-Write。
存储约束:r
根据操作符使用一个通用寄存器,由GCC自行选取。
a 根据操作符使用 %rax %eax %ax %al
b 根据操作符使用 %rbx %ebx %bx %bl
c 根据操作符使用 %rcx %ecx %cx %cl
d 根据操作符使用 %rdx %edx %dx %dl
m 直接使用内存
注:1. output/input可以指定多个接口,之间以","分隔。但最多不超过10个。
2. 操作约束并没有一一列举,还有一些不太常用的如"=&a"()可以在自行google。
3.3 指定约束条件后,对C变量/常量的真实操作
本节会详细分析三种操作约束后,真实的操作情况。其它约束可以以此类推。
3.3.1为了方便对比,我们先看output域中,操作约束为"+"(Read-Write)的情况
先看将例程中的output域修改,并编译为汇编的结果:
这里可以看出,output域在"+"的情况下:
1. 程序先将变量 c 的值载入寄存器 %bl(虽然是先载入 %eax, 而后传到 %ebx)
2. 执行汇编语句
3. 将 %bl 的值写回 c 的内存地址
3.3.2 output域中,操作约束为"="(Write-Only)的情况
先看将例程中的output域修改,并编译为汇编的结果:
output域,在 "=" (Write-Only)时,程序不会将变量c的值载入
("r")指定的寄存器 %bl:
1
. 执行汇编语句
2. 将 %bl 的值写回 c 的内存地址
3.3.3 input域的情况
同样,修改
例程中的input域,并编译为汇编的结果:
input域就没有必要再指定操作约束是 "+"还是"=",因为作为输入域,本来就是会载入变量值的;但是因为同样的原因,输入域也
不会再把该寄存器的值写回变量所在的内存;也就是说,如果不作其它的处理,该寄存器中的值会被丢掉,程序流程如下:
1. 程序先将变量 c 的值载入寄存器 %al(整体装入到 %eax)
2. 执行汇编语句
对比了以上三种情况,我们可以在内嵌汇编时,灵活使用操作约束来操作 c的变量。
4 顺带说下占位符
在前面第二节说过,寄存器要写为%%rax %%eax格式;%0 %1为占位符使用。
占位符可以理解为:output/input域指定的,从头开始数,第一个为 %0,第二个为 %1,以此类推。
例如:
-
: "+r" (c)
-
: "a" (c1), "b" (c2)
这时候,c c1 c2三个变量对应寄存器的占位符分别对应为:%0 %1 %2
占位符的用处:
1)比如 c 存放于一个GCC选择的通用寄存器,我们并不知道是哪个寄存器,所以只能通过 %0来调用
2)对c1的使用,可以使用 %%eax 也可以 %1。但是当程序需要改动时,%1明显会减少很多工作量
另外:占位符最多只能有10个,从 %0 到 %9
END.
阅读(1021) | 评论(0) | 转发(0) |