汇编快速认识

作者: | 更新日期:

之前反汇编服务二进制,根据自己的汇编知识找到了问题, 今天记录一下汇编知识.

本文首发于公众号:天空的代码世界,微信号:tiankonguse

零、前言

先看一段汇编代码吧.

static inline uint32_t min_cmp_set(volatile int*l, int o, int n) {
	unsigned char r;
	__asm__ volatile (
			"lock;"
			"cmpxchgl  %3, %1;"
			"sete      %0;    "
			: "=a" (r)
			: "m" (*l), "a" (o), "r" (n)
			: "cc", "memory");
	return r;
}

还有下面使用性能工具和反汇编出来的代码.

mov    0x38(%rax),%rdi
mov    $0x1,%esi
add    $0xcf0,%rdi
callq  428
xor    %eax,%eax
add    $0x8,%rsp
retq   
callq  434
mov    0x38(%rax),%rdi
mov    $0x1,%esi
add    $0xc78,%rdi
callq  449
or     $0xffffffffffffffff,%eax
jmp    42a

看第一个代码, 完全不知道什么意思, 看第二个代码,大概能猜出几个意思,但是也不是很确定.
所以我们需要先了解一下汇编的基础知识, 然后就可以轻松的看上面的代码了.

一、寄存器

引用寄存器时在前加百分号,如movl %eax, %ebx
寄存器有这些:

  • 8个32-bit寄存器 %eax,%ebx,%ecx,%edx,%edi,%esi,%ebp,%esp
  • 8个16-bit寄存器:%ax,%bx,%cx,%dx,%di,%si,%bp,%sp(32-bit寄存器的低16位)
  • 8个8-bit寄存器:%ah,%al,%bh,%bl,%ch,%cl,%dh,%dl。(16-bit寄存器的高8位和低8位)
  • 6个段寄存器:%cs(code),%ds(data),%ss(stack), %es,%fs,%gs
  • 3个控制寄存器:%cr0,%cr2,%cr3
  • 6个debug寄存器:%db0,%db1,%db2,%db3,%db6,%db7
  • 2个测试寄存器:%tr6,%tr7
  • 8个浮点寄存器栈:%st(0),%st(1),%st(2),%st(3),%st(4),%st(5),%st(6),%st(7)

二、基础知识

  • 命令操作顺序是从左到右的.
  • 立即数就是一个数字.使用立即数,要在数前面加符号$
  • 符号常数相当于给立即数定义了一个名字。
  • 操作数的长度使用指令后的符号表示b(byte, 8-bit), w(word, 16-bits), l(long, 32-bits)
    如果没有指定,编译器自己推断,推不出来了报错。
  • 段内调用和跳转指令为callretjmp
    段间调用和跳转指令为lcalllretljmp
  • 操作码前缀被用在下列的情况:
    字符串重复操作指令(rep,repne)
    指定被操作的段(cs,ds,ss,es,fs,gs)
    进行总线加锁(lock) 指定地址和操作的大小(data16,addr16)
  • 内存引用的格式为: section:[base+index*scale+displacement]

三、GCC Inline ASM

GCC 支持在C/C++代码中嵌入汇编代码,这些汇编代码被称作GCC Inline ASM——GCC内联汇编。 __asm__用来声明一个汇编表达式。
__volatile__ 是可选的,向GCC声明不能对汇编代码进行优化.

__asm__ __volatile__("Instruction List" : Output : Input : Clobber/Modify);
__asm__  __volatile__(指令部:输出部:输入部:损坏部);

1. 解释

  • 指令部: 数字加上前缀%,如%1、%0等,表示需要使用寄存器的样板操作数。
  • 输出部: 规定对输出变量,即目标操作数如何结合的约束条件。
    每个输出约束以“=”号开头,然后是一个字母表示对操作数类型的说明,然后是关于变量结合的约束。
  • 输入部约束的格式和输出约束相似,但不带“=”号。
  • 损坏部: 用于储存中间结果。

2. 约束条件

约束条件 含义如下:

  • “m”、”v”和”o” 表示内存单元
  • “r” 表示任何寄存器
  • “q” 表示寄存器eax,ebx,ecx,edx之一
  • “i”和”h” 表示直接操作数
  • “E”和”F” 表示浮点数
  • “g” 表示任意
  • “a”,”b”, “c” “d” 分别表示要使用寄存器eax ebx ecx和edx
  • “S”和”D” 分别表示要使用寄存器esi和edi
  • “I” 表示常数(0至31)

3. 语法规则

后面的部分为空, 后面的冒号可以忽略, 前面的为空,前面的冒号不能忽略.
这个和函数默认参数一个道理,不然没法区分谁是谁了.

另外有冒号了就是C/C++格式的汇编, 没冒号就是内联汇编了. 对于内联汇编访问寄存器使用一个百分号,另一个使用两个.

四、汇编语法

这里只有常见的语法。

  • MOV, PUSH, POP 赋值,入栈,出栈
  • BSWAP(byte swap), XCHG, CMPXCHG,XADD(exchange and add), XLAT(translate) 交换
  • ADD,INC, SUB,DEC, MUL, DIV, CMP 加减乘除,比较
  • AND, OR, XOR, NOT, TEST,SHL,SHR,ROL,ROR 位操作
  • MOVS(move string), CMPS, LODS(load string), STOS(store string), REP(repeat) 串操作
  • JMP, CALL, RET(return), RETF(return far) 无条件跳转
  • JG(jump when greater), JL, JZ(jump when has zero flag), JNG, JNL 条件跳转
  • LOOP 循环控制
  • INT(interrupt), INTO(overflow interrupt), IRET(interrupt return) 中断
  • HLT(halt), WAIT, ESC(escape), LOCK, NOP(no operation), STI(set interrupt), CLI(clear interrupt) 其他

五、参考资料

好了, 有了这些基础只是我已经轻松看懂反汇编的所有代码了, 下面是对于的参考资料,ibm的资料果然很全。

六、其他文章

七、关于作者

曾是一名ACMer, 现在是鹅长视频部门的后台开发。
这里主要记录工作中的技术架构与经验,计算机相关的技术,数学、算法、生活上好玩的东西。
长按二维码关注作者, 了解作者发布的最新好玩的东西


长按图片关注公众号, 接受最新文章消息.

本文首发于公众号:天空的代码世界,微信号:tiankonguse
如果你想留言,可以在微信里面关注公众号进行留言。

关注公众号,接收最新消息

tiankonguse +
穿越