Re:反汇编C代码中某些指令的含义(使用gdb v反汇编)13.2,使用g v.13.1.0编译,带有-std=c++23、-g和-o标志)。
大部分的说明和它们的目的可以通过搜索关于这个主题的书籍和网站找到,但有一行只有部分解释,另一行没有解释,我可以找到任何。这些问题的灵感来自以下内容,取自gdb程序集转储:
Dump of assembler code for function _ZdlPvy:
0x00007ff75cdb17f0 <+0>: jmp *0x8a92(%rip) # 0x7ff75cdba288 <__imp__ZdlPvy>
0x00007ff75cdb17f6 <+6>: nop
0x00007ff75cdb17f7 <+7>: nop
Dump of assembler code for function __imp__ZdlPvy:
0x00007ff75cdba288 <+0>: push %rax
0x00007ff75cdba289 <+1>: ret
0x00007ff75cdba28a <+2>: rex.X
0x00007ff75cdba28b <+3>: rex.WX (bad)
0x00007ff75cdba28d <+5>: jg 0x7ff75cdba28f <__imp__ZdlPvy+7>
0x00007ff75cdba28f <+7>: add %dl,%al
然而,当我5天后拆解相同的代码时,<__imp__ZdlPvy>结果是这样的:
Dump of assembler code for function __imp__ZdlPvy:
0x00007ff75cdba288 <+0>: push %rax
0x00007ff75cdba289 <+1>: ret
0x00007ff75cdba28a <+2>: stos %al,%es:(%rdi)
0x00007ff75cdba28b <+3>: or $0xf8,%al
0x00007ff75cdba28d <+5>: jg 0x7ff75cdba28f <__imp__ZdlPvy+7>
0x00007ff75cdba28f <+7>: add %dl,%al
我的问题是:
雷克斯.X在这里干什么?雷克斯.WX(bad)在这里做什么,它是什么意思?or指令如何取代雷克斯.WX(假设它是)?为什么同一个例程的第二次反汇编会将雷克斯.X替换为x1指令呢?为什么每次反汇编都有不同,即使代码没有改变,而且整个过程中只在gdb中运行了几次?
有关更多上下文:_ZdlPvy是在具有以下反汇编的例程中找到的。(从代码中可以看出,有一个分段错误,由insert()方法引起。这是故意留下的一个难题,让我来解决。)
Dump of assembler code for function _ZN4MathIiED1Ev:
0x00007ff75cdb3430 <+0>: push %rbp
0x00007ff75cdb3431 <+1>: mov %rsp,%rbp
0x00007ff75cdb3434 <+4>: sub $0x30,%rsp
0x00007ff75cdb3438 <+8>: mov %rcx,0x10(%rbp)
0x00007ff75cdb343c <+12>: movl $0x0,-0x4(%rbp)
0x00007ff75cdb3443 <+19>: jmp 0x7ff75cdb3464 <_ZN4MathIiED1Ev+52>
0x00007ff75cdb3445 <+21>: mov 0x10(%rbp),%rax
0x00007ff75cdb3449 <+25>: mov 0x8(%rax),%rax
0x00007ff75cdb344d <+29>: mov -0x4(%rbp),%edx
0x00007ff75cdb3450 <+32>: movslq %edx,%rdx
0x00007ff75cdb3453 <+35>: shl $0x2,%rdx
0x00007ff75cdb3457 <+39>: add %rdx,%rax
0x00007ff75cdb345a <+42>: movl $0x0,(%rax)
0x00007ff75cdb3460 <+48>: addl $0x1,-0x4(%rbp)
0x00007ff75cdb3464 <+52>: mov 0x10(%rbp),%rax
0x00007ff75cdb3468 <+56>: mov (%rax),%eax
0x00007ff75cdb346a <+58>: cmp %eax,-0x4(%rbp)
0x00007ff75cdb346d <+61>: jl 0x7ff75cdb3445 <_ZN4MathIiED1Ev+21>
0x00007ff75cdb346f <+63>: mov 0x10(%rbp),%rax
0x00007ff75cdb3473 <+67>: movq $0x0,0x8(%rax)
0x00007ff75cdb347b <+75>: mov 0x10(%rbp),%rax
0x00007ff75cdb347f <+79>: mov 0x8(%rax),%rax
0x00007ff75cdb3483 <+83>: test %rax,%rax
0x00007ff75cdb3486 <+86>: je 0x7ff75cdb3495 <_ZN4MathIiED1Ev+101>
0x00007ff75cdb3488 <+88>: mov $0x4,%edx
0x00007ff75cdb348d <+93>: mov %rax,%rcx
0x00007ff75cdb3490 <+96>: call 0x7ff75cdb17f0 <_ZdlPvy>
0x00007ff75cdb3495 <+101>: nop
0x00007ff75cdb3496 <+102>: add $0x30,%rsp
0x00007ff75cdb349a <+106>: pop %rbp
0x00007ff75cdb349b <+107>: ret
这会在下面的main()反汇编中弹出:
main (argc=1, args=0x7297a0) at Try_Out.cpp:275
275 pointier.insert(0, 5);
Dump of assembler code for function main(int, char**):
0x00007ff75cdb16d0 <+0>: push %rbp
0x00007ff75cdb16d1 <+1>: push %rbx
0x00007ff75cdb16d2 <+2>: sub $0x48,%rsp
0x00007ff75cdb16d6 <+6>: lea 0x40(%rsp),%rbp
0x00007ff75cdb16db <+11>: mov %ecx,0x20(%rbp)
0x00007ff75cdb16de <+14>: mov %rdx,0x28(%rbp)
0x00007ff75cdb16e2 <+18>: call 0x7ff75cdb18c7 <__main>
0x00007ff75cdb16e7 <+23>: movl $0x2,-0x4(%rbp)
0x00007ff75cdb16ee <+30>: lea -0x20(%rbp),%rax
0x00007ff75cdb16f2 <+34>: mov $0x1,%edx
0x00007ff75cdb16f7 <+39>: mov %rax,%rcx
0x00007ff75cdb16fa <+42>: call 0x7ff75cdb33f0 <_ZN4MathIiEC1Ei>
=> 0x00007ff75cdb16ff <+47>: lea -0x20(%rbp),%rax
0x00007ff75cdb1703 <+51>: mov $0x5,%r8d
0x00007ff75cdb1709 <+57>: mov $0x0,%edx
0x00007ff75cdb170e <+62>: mov %rax,%rcx
0x00007ff75cdb1711 <+65>: call 0x7ff75cdb33c0 <_ZN4MathIiE6insertEii>
0x00007ff75cdb1716 <+70>: lea -0x20(%rbp),%rax
0x00007ff75cdb171a <+74>: mov $0xa,%r8d
0x00007ff75cdb1720 <+80>: mov $0x1,%edx
0x00007ff75cdb1725 <+85>: mov %rax,%rcx
0x00007ff75cdb1728 <+88>: call 0x7ff75cdb33c0 <_ZN4MathIiE6insertEii>
0x00007ff75cdb172d <+93>: lea -0x20(%rbp),%rax
0x00007ff75cdb1731 <+97>: mov $0x0,%edx
0x00007ff75cdb1736 <+102>: mov %rax,%rcx
0x00007ff75cdb1739 <+105>: call 0x7ff75cdb3390 <_ZN4MathIiE4at_vEi>
0x00007ff75cdb173e <+110>: mov %eax,%edx
0x00007ff75cdb1740 <+112>: mov 0x3c99(%rip),%rax # 0x7ff75cdb53e0 <__fu0__ZSt4cout>
--Type <RET> for more, q to quit, c to continue without paging--c
0x00007ff75cdb1747 <+119>: mov %rax,%rcx
0x00007ff75cdb174a <+122>: call 0x7ff75cdb1800 <_ZNSolsEi>
0x00007ff75cdb174f <+127>: mov %rax,%rcx
0x00007ff75cdb1752 <+130>: lea 0x38f7(%rip),%rax # 0x7ff75cdb5050
0x00007ff75cdb1759 <+137>: mov %rax,%rdx
0x00007ff75cdb175c <+140>: call 0x7ff75cdb17f8 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
0x00007ff75cdb1761 <+145>: mov %rax,%rbx
0x00007ff75cdb1764 <+148>: lea -0x20(%rbp),%rax
0x00007ff75cdb1768 <+152>: mov $0x1,%edx
0x00007ff75cdb176d <+157>: mov %rax,%rcx
0x00007ff75cdb1770 <+160>: call 0x7ff75cdb3390 <_ZN4MathIiE4at_vEi>
0x00007ff75cdb1775 <+165>: mov %eax,%edx
0x00007ff75cdb1777 <+167>: mov %rbx,%rcx
0x00007ff75cdb177a <+170>: call 0x7ff75cdb1800 <_ZNSolsEi>
0x00007ff75cdb177f <+175>: lea 0x38d5(%rip),%rax # 0x7ff75cdb505b
0x00007ff75cdb1786 <+182>: mov %rax,%rdx
0x00007ff75cdb1789 <+185>: mov 0x3c50(%rip),%rax # 0x7ff75cdb53e0 <__fu0__ZSt4cout>
0x00007ff75cdb1790 <+192>: mov %rax,%rcx
0x00007ff75cdb1793 <+195>: call 0x7ff75cdb17f8 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
0x00007ff75cdb1798 <+200>: mov $0x7a120,%ecx
0x00007ff75cdb179d <+205>: call 0x7ff75cdb2eb0 <usleep>
0x00007ff75cdb17a2 <+210>: mov $0x0,%ebx
0x00007ff75cdb17a7 <+215>: lea -0x20(%rbp),%rax
0x00007ff75cdb17ab <+219>: mov %rax,%rcx
0x00007ff75cdb17ae <+222>: call 0x7ff75cdb3430 <_ZN4MathIiED1Ev>
0x00007ff75cdb17b3 <+227>: mov %ebx,%eax
0x00007ff75cdb17b5 <+229>: jmp 0x7ff75cdb17d1 <main(int, char**)+257>
0x00007ff75cdb17b7 <+231>: mov %rax,%rbx
0x00007ff75cdb17ba <+234>: lea -0x20(%rbp),%rax
0x00007ff75cdb17be <+238>: mov %rax,%rcx
0x00007ff75cdb17c1 <+241>: call 0x7ff75cdb3430 <_ZN4MathIiED1Ev>
0x00007ff75cdb17c6 <+246>: mov %rbx,%rax
0x00007ff75cdb17c9 <+249>: mov %rax,%rcx
0x00007ff75cdb17cc <+252>: call 0x7ff75cdb2e60 <_Unwind_Resume>
0x00007ff75cdb17d1 <+257>: add $0x48,%rsp
0x00007ff75cdb17d5 <+261>: pop %rbx
0x00007ff75cdb17d6 <+262>: pop %rbp
0x00007ff75cdb17d7 <+263>: ret
所有这些都是从下面的代码中分解出来的:
#include <iostream>
#include <unistd.h>
#include <memory>
template <typename T> class Math
{
public:
int size = 2; T* ptr;
Math (int size)
{ T* ptr = new T(*ptr) ;}
T at_v (int place)
{ return ptr[place] ;}
void insert (int place, int value)
{ ptr[place] = value ;}
};
int main()
{
int size = 2 ;
Math <int> pointier(1) ;
pointier.insert(0, 5) ;
pointier.insert(1, 10) ;
std::cout << pointier.at_v(0) << " and also " << pointier.at_v(1) ;
std::cout << "\n\n"; usleep(500000) ;
}
这仅仅是一个关于asm指令的意义的查询,在网站和文献中搜索都是空的。我想知道,因为它会让我更好地弄清楚如何从反汇编中调试代码:我打算自己做这个调试,但需要帮助理解几行。
1条答案
按热度按时间mbzjlibv1#
反汇编程序可以尝试解码不可执行的数据。机器代码毕竟只是一种数据类型-所以一些随机数据可以有一个有效的(或不那么有效的)机器代码解释。你可以命令反汇编程序解码一个数据段。代码部分有时也可以包含函数之间的不可执行常量。
雷克斯是64位x86机器码中的前缀。它实际上应该稍微修改下一条指令的含义:
REX.W
使指令为64位(默认情况下,大多数指令在x86中为8位或32位)REX.X
表示新寄存器r8-r15
之一用作索引REX.WX
两者都可以那么,为什么反汇编程序打印雷克斯前缀,而不是将它们作为下一条指令的一部分呢?因为代码有两个雷克斯前缀-这是非法的。CPU不会接受这样的机器码,并将触发“非法操作码”中断。这也是
(bad)
的意思--坏指令。您看到的代码是一个过程链接表(PLT)。它包含函数的存根,这些存根实际上位于动态库(
.so
)中。动态库在运行时加载,因此编译器和链接器不可能知道函数将位于何处。第一个
jmp
是执行的代码-它只是读取真实的地址并跳转到它。两个nop
用于填充。接下来的8个字节是一个函数的64位地址-或者更确切地说是一个占位符,应该写在哪里。最初,它包含一个特殊的“从.so中查找和加载地址”函数的地址-允许延迟加载。在运行时,该地址将被来自
.so
的函数的真实的地址覆盖。