虽然先前已经把 phase_1 和 phase_2 做出来了, 但其实是参考了网络上的答案, 仅仅是大概知道了关键汇编代码。但其实并没有真的懂。为啥呢?因为很多模棱两可的地方是靠猜测的,而猜测是脆弱的。
重新看 phase_1, 第一个门槛是 string_length 函数。尝试逐句翻译回 C 代码。
前提条件: 知道 eax 存储返回值, 知道 rdi 存储函数第一个参数。使用Intel风格的汇编。
(gdb) disassemble string_length
Dump of assembler code for function string_length:
0x000000000040131b <+0>: cmp BYTE PTR [rdi],0x0
0x000000000040131e <+3>: je 0x401332 <string_length+23>
0x0000000000401320 <+5>: mov rdx,rdi
0x0000000000401323 <+8>: add rdx,0x1
0x0000000000401327 <+12>: mov eax,edx
0x0000000000401329 <+14>: sub eax,edi
0x000000000040132b <+16>: cmp BYTE PTR [rdx],0x0
0x000000000040132e <+19>: jne 0x401323 <string_length+8>
0x0000000000401330 <+21>: repz ret
0x0000000000401332 <+23>: mov eax,0x0
0x0000000000401337 <+28>: ret
End of assembler dump.
尝试反汇编为 C 代码:
1)返回值类型:看到了对 eax 寄存器的操作。基本上是 int 类型。C代码为:
int string_length()
{
...
}
2)cmp BYTE PTR [rdi], 0x0
: 这句是 rdi 寄存器里的值表示的内存地址里的值,和0作比较。用C代码表示为:
int string_length(const char* str)
{
if (*str == '\0')
{
return 0;
}
}
-
je 0x401332 <string_length+23>
: 和上一句连在一起的, return 0. -
mov rdx, rdi
: 把函数第一个参数,赋值到一个新的变量里头,大概是:
int string_length(const char* str)
{
if (*str == '\0')
{
return 0;
}
const char* ptr = str;
}
-
add rdx, 0x1
: 新赋值的变量加1:
int string_length(const char* str)
{
if (*str == '\0')
{
return 0;
}
const char* ptr = str;
ptr += 1;
}
-
mov eax, edx
: 把刚刚加1的变量,放到 eax 寄存器, 也就是和返回值有关系。没法直接写C代码。继续看。 -
sub eax, edi
: 让 eax 寄存器减掉 edi 寄存器。C代码:
int string_length(const char* str)
{
if (*str == '\0')
{
return 0;
}
const char* ptr = str;
ptr += 1;
int ret = ptr - str;
return ret;
}
-
cmp BYTE PTR [rdx], 0x0
: 把 rdx 寄存器里的值对应的内存地址处的值, 和0比较。看不出来C代码。继续看汇编. -
jne 0x401323 <string_length+8>
: 如果刚刚的比较结果不相等,也就是说 [rdx] != 0, 那么跳转到add rdx, 0x1
这句。代码:
int string_length(const char* str)
{
if (*str == '\0')
{
return 0;
}
const char* ptr = str;
int ret;
hello:
ptr += 1;
ret = ptr - str;
if (*ptr != '\0')
{
goto hello;
}
return ret;
}
-
repz ret
: 没啥高深的,就是跳转到 ret
经过上面这段梳理,写出来的C代码很混乱。goto 和 if 的组合,基本上是等价于 while 循环:文章来源:https://www.toymoban.com/news/detail-791302.html
int string_length(const char* str)
{
if (*str == '\0')
{
return 0;
}
const char* ptr = str;
int ret;
do {
ptr += 1;
ret = ptr - str;
} while (*ptr != '\0')
return ret;
}
再进一步, 感觉 ret 的赋值做了重复计算, do while 也不如 while 直接:文章来源地址https://www.toymoban.com/news/detail-791302.html
int string_length(const char* str)
{
if (*str == '\0')
{
return 0;
}
const char* ptr;
for (ptr = str + 1; ptr != '\0'; ptr++);
return ptr - str;
}
到了这里,关于CSAPP - 反编译 string_length的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!