AT&T汇编语法和Intel语法大致相同,一个从左到右,一个从右到左,AT&T是寄存器前面加%,立即数前面加$,
Intel语法 | AT&T语法 |
mov eax,8 | movl $8,%eax |
mov ebx,0ffffh | movl $0xffff,%ebx |
int 80h | int $0x80 |
立即数16位后面是h | 16位用0x表示 |
__asm__ __volatile__("asm routine":output:intput:modify)
//__volatile__ 避免"asm"指令被删除,移动或组合
static inline unsigned long get_limit(unsigned long segment)
{
unsigned long _limit;
__asm__("lsll %1,%0"
:"=r"(_limt):"r"(segment));
return _limit+1;
}
寄存器%0,%1,一次从output中用到的寄存器开始编码。=表示输出,将%0寄存器(eax)中的值输出到_limit中,segment放到%1寄存器中。
movl segment,%ebx
lsll %ebx,%eax
movl %eax,_limit
先分析输出输入部分,确定寄存器编号与输入输出部分代码
- "=r"(_limit)//将一个寄存器如eax中的值放入_limit中
- "r"(segment)//将segment的值放入寄存器如ebx中
再分析asm routine部分
下面表格是汇编中一些字母的含义
=&a:&表示寄存器不能重复
=表示是输出
双%号是因为有%1
\n换行,\t tab为了让gcc把嵌入式汇编代码翻译成一般的汇编代码时能够保证换行和留有一定的空格。
jne 1b:往后找到编号为1的代码
jmp 3f:往前找到编号为3的代码
下面看如下代码
- eax-_res-%0
- esi-d0-%1-cs(cs为输入,前面的1表示将cs放入%1寄存器,即esi中)
- edi-d1-%2-ct(ct为输入,前面的2表示将ct放入%2寄存器,即edi中)
上边的嵌入式汇编会被翻译成:
1:lodsb//装入串操作数,即从[esi]传送到al寄存器,然后esi指向串中下一个元素
scasb//扫描串操作数,即从al中减去es:[edi],不保留结果,只改变标志
jne2f//如果两个字符不相等,则跳转到标号2
testb %al,%al //判断是否达到字符串末尾,如果al是0,AND结果是0,zf位为1,反之分别为1,0
//AT&T汇编是UNIX下惯用的汇编格式
//l,w,b是AT&T汇编中用来表示操作属性的限定符,l是长字(4字节),w是双字,b是一个字节
jne 1b //没到末尾跳转回去
xorl %eax,%eax//清零eax
jmp 3f
2:sbbl %eax,%eax//SBB带借位减法,格式SBB %SRC,%DST,执行的操作:(DST)<-(DST)-(SRC)-CF
orb $1,al
3:
eax