通过反汇编定位bug你需要了解的基础知识

89 阅读5分钟

汇编指令

标题高级语言描述
mov ax, bxax=bx
add ax, bxax = ax + bx
bl跳转指令,但跳转之前,会在寄存器R14 中保存PC 的当前内容,因此,可以通过将R14 的内容重新加载到PC 中,来返回到跳转指令之后的那个指令处执行。该指令是实现子程序调用的一个基本但常用的手段。
B最简单的跳转指令。一旦遇到一个 B 指令,ARM 处理器将立即跳转到给定的目标地址,从那里继续执行。
uxtb将4个字节的其中一个字节提取出来,然后转成一个新的32位整型
ret相当于高级语言的return
6f615c:	d00057e3 	adrp	x3, 11f4000 <_ZZN7cocos2d13AsyncTaskPool11ThreadTasks7enqueueESt8functionIFvPvEES3_S2_IFvvEEE12__FUNCTION__+0x4a60>
6f6160:	52800041 	mov	w1, #0x2                   	// #2
6f6164:	9100dfa2 	add	x2, x29, #0x37
6f6168:	913de063 	add	x3, x3, #0xf78
6f616c:	97ff8ad0 	bl	6d8cac <_Z17luaval_to_booleanP9lua_StateiPbPKc>
6f6170:	53001c00 	uxtb	w0, w0
6f6174:	35000100 	cbnz	w0, 6f6194 <_Z28lua_cocos2dx_Node_setVisibleP9lua_State+0xc8> // 对应的是这里
6f6178:	d00057e1 	adrp	x1, 11f4000 <_ZZN7cocos2d13AsyncTaskPool11ThreadTasks7enqueueESt8functionIFvPvEES3_S2_IFvvEEE12__FUNCTION__+0x4a60>
6f617c:	aa1503e0 	mov	x0, x21
6f6180:	913e4021 	add	x1, x1, #0xf90
6f6184:	d2800002 	mov	x2, #0x0                   	// #0
6f6188:	9403ee4f 	bl	7f1ac4 <tolua_error>
6f618c:	52800000 	mov	w0, #0x0                   	// #0
6f6190:	17ffffea 	b	6f6138 <_Z28lua_cocos2dx_Node_setVisibleP9lua_State+0x6c>
6f6194:	f94002c2 	ldr	x2, [x22]
6f6198:	aa1603e0 	mov	x0, x22
6f619c:	3940dfa1 	ldrb	w1, [x29,#55]
6f61a0:	f940b842 	ldr	x2, [x2,#368]
6f61a4:	d63f0040 	blr	x2
6f61a8:	aa1503e0 	mov	x0, x21
6f61ac:	2a1403e1 	mov	w1, w20
6f61b0:	940e4738 	bl	a87e90 <lua_settop>
6f61b4:	2a1403e0 	mov	w0, w20
6f61b8:	17ffffe0 	b	6f6138 <_Z28lua_cocos2dx_Node_setVisibleP9lua_State+0x6c>
6f61bc:	97f8471d 	bl	507e30 <__stack_chk_fail@plt>

编译器函数名称修饰符

是为了保证函数名字的唯一性。

_Z28lua_cocos2dx_Node_setVisibleP9lua_State

P 是指针参数的意思

  • 全局函数: 以“_Z”开头,然后是函数名字符的个数28,"lua_cocos2dx_Node_setVisible".length=28,,接着是函数名,最后是函数参数的别名。

  • 类、命名空间中的变量函数

以“_ZN”开头,然后是变量或函数所在名字空间或类名字的字符长度,然后接着的是真正的名字空间或类名,然后是变量或函数名的长度和变量或函数名,后面紧跟字母“E”,最后如果是函数的话则跟参数别名,如果是变量则什么都不用加。

  • 构造函数和析构函数

以”_ZN”开头,然后是构造函数所在名字空间和类名字的字符长度,然后接着的是真正的名字空间或类名,然后构造函数接“C1”或者“C2”,析构函数接“D1”或者“D2”,然后加上字母“E”,最后接函数参数别名结束。

int lua_cocos2dx_Node_setVisible(lua_State* tolua_S)

立即数

立即数就是写在指令里的常数。 还是用mov操作举例子,mov 12, %rax,那么这个 12 就在操作语句里。那么 12 相当于指令里的立即数。

汇编基础知识

7f1018: 940a5b9e 	bl	a87e90 <lua_settop>

操作码(94对应arm指令bl) 条件码(0a无条件跳转) 偏移量(5b9e)

7f1018+5b9e=7F6BB6

                                     这个地址,对应的就是lua_settop的地址
7f1018:	940a5b9e 	bl	a87e90 <lua_settop>
  
0000000000a87e90 <lua_settop>:
  a87e90:	d10083ff 	sub	sp, sp, #0x20
  a87e94:	a90053f3 	stp	x19, x20, [sp]
  a87e98:	f9000bfe 	str	x30, [sp,#16]
  a87e9c:	aa0003f3 	mov	x19, x0
  a87ea0:	37f80381 	tbnz	w1, #31, a87f10 <lua_settop+0x80>
  a87ea4:	f9401004 	ldr	x4, [x0,#32]
  a87ea8:	937d7c34 	sbfiz	x20, x1, #3, #32
  a87eac:	f9401402 	ldr	x2, [x0,#40]

str指令

str	x2, [x29,#72]

STR指令用于从源寄存器x2中将一个32位的字数据传送到存储器中x29中

stp 指令是 str 的变种指令,p 可以理解成 pair 的意思,可以同时操作两个寄存器。

  • FP:栈顶指针,指向一个栈帧的顶部,当函数发生跳转时,会记录当时的栈的起始位置。
  • SP:栈指针(也称为栈底指针),指向栈当前的位置,
  • LR:链接寄存器,保存函数返回的地址。

寄存器名全部是 x1 、 x2 、 x10 了。