C++ 这个asm代码的意义是什么? obj.CurrSize-=大小; 0x00000000003ad2d7:mov eax,0x0 0x00000000003ad2dc:测试rax,rax 0x00000000003ad2df:je 0x3ad2e6 0x00000000003ad2e1:调用0x0 0x00000000003ad2e6:mov rax,0xFFFFFFFFFF60 0x00000000003ad2ed:子rbx,r15 0x00000000003ad2f0:添加QWORD PTR fs:[rax],rbx`
为什么要测试零,如果是零,跳过一条指令,否则也要这样做?阅读一个无关的问题,我想我找到了你奇怪代码的来源 这段代码很可能来自与线程相关的C++11功能的扩展,特别是使用C++ 这个asm代码的意义是什么? obj.CurrSize-=大小; 0x00000000003ad2d7:mov eax,0x0 0x00000000003ad2dc:测试rax,rax 0x00000000003ad2df:je 0x3ad2e6 0x00000000003ad2e1:调用0x0 0x00000000003ad2e6:mov rax,0xFFFFFFFFFF60 0x00000000003ad2ed:子rbx,r15 0x00000000003ad2f0:添加QWORD PTR fs:[rax],rbx`,c++,assembly,x86,x86-64,clang++,C++,Assembly,X86,X86 64,Clang++,为什么要测试零,如果是零,跳过一条指令,否则也要这样做?阅读一个无关的问题,我想我找到了你奇怪代码的来源 这段代码很可能来自与线程相关的C++11功能的扩展,特别是使用\uugthread\u active\u p()检查pthread库是否实际链接到了 在libstdc++中,大多数可能需要处理线程问题的代码(但在不需要线程支持的情况下有合理的回退)都是杂乱无章的 obj.CurrSize -= size; 0x00000000003ad2d7 <+183>: mov eax,0
\uugthread\u active\u p()
检查pthread
库是否实际链接到了
在libstdc++中,大多数可能需要处理线程问题的代码(但在不需要线程支持的情况下有合理的回退)都是杂乱无章的
obj.CurrSize -= size;
0x00000000003ad2d7 <+183>: mov eax,0x0
0x00000000003ad2dc <+188>: test rax,rax
0x00000000003ad2df <+191>: je 0x3ad2e6 <+198>
0x00000000003ad2e1 <+193>: call 0x0
0x00000000003ad2e6 <+198>: mov rax, 0xffffffffffffff60
0x00000000003ad2ed <+205>: sub rbx,r15
0x00000000003ad2f0 <+208>: add QWORD PTR fs:[rax],rbx`
这通常归结为检查符号\uu pthread\u key\u create
是否定义为与NULL
不同的内容。这里的技巧是,这样一个函数是用\uuuu属性
声明的,因此,如果没有提供定义(即,如果pthread
库没有链接),链接器只会将其引用解析为NULL,而不是抱怨
因此,您在代码中看到的是编译器留下来执行线程相关工作的检查(例如,获取保护某些共享资源的互斥锁)。预链接代码可能类似于:
if(__gthread_active_p())
在这里,您可以看到所有解析为NULL
指针的\pthread
符号。当然,生成的代码非常愚蠢-编译器不知道链接器是否将使用-lpthread
调用,链接器只是执行愚蠢的替换-再次运行优化器为时已晚(除非启用LTO,但这是一个完全不同的游戏)
您可以看到类似的模式:尝试启用/禁用链接完整二进制文件(右侧带有11010标题的按钮),以及在命令行上添加/删除-pthread
现在,我没有完全复制您的结果,但可能是因为使用了不同版本的
libstdc++
,或者代码中使用了不同的线程感知组件(我刚刚尝试了std::mutex
和std::shared_ptr
)。不,call 0x0
只是调用下一条指令,不是空指针。这是一个已经静态链接的程序的disasm(gdb disasm的输出)。我不确定,IIRC通常gdb转储as调用0x3ad2e6
,类似于上面的相对跳转。尽管如此,如果它像你说的那样,看起来像是手写代码来停止反编译程序之类的-在函数本身中插入一个伪调用会对重建函数入口点/块的启发式造成严重破坏。哦,糟糕,是的,那是一个空指针加载,而不是mov-eax,imm32
。我只是不习惯GDB版本的英特尔语法objdump
将打印DWORD PTR:0
。(@vladon)我用gdb测试过。绝对0的负载为mov eax,DWORD PTR ds:0x0
,但mov eax,imm32
为mov eax,0x0
。也许最初的代码是moveax,OFFSET\u pthread\u key\u create
?是的,我的意思是立即加载。我真的不知道OFFSET
语法,通常在nasm
amov-reg,label
是指立即加载label的地址,间接加载是mov-reg,[label]
(DWORD-PTR
通常被省略,如果可以通过目标寄存器的大小推断出来的话)。抱歉造成混淆。如果rax
的上半部分中有任何非零位,将执行调用0x0
。那么接下来是什么呢?没有堆栈清理的ret
?然后以递归的形式再次执行这些代码,我不知道。什么C++语句/汇编指令遵循你所张贴的?@彼得科德斯谢谢。这是我们的内部代码。它真的是叮当作响3.9.1与-O2。但如果是,则永远不会执行调用0x0。为什么会有测试和je过度指导?嗯…这是从链接二进制文件中进行的GDB反汇编吗?您是否可以发布objdump
输出,这样我们就可以查看机器代码字节,以确保这是跳转到地址零,还是跳转到下一条指令。(请再次确认它是链接的二进制文件,而不是带有占位符的对象文件)。(或者只处理那个测试用例,因为这样会更有用。)@PeterCordes调用0x0的机器代码这里是e8 1a 2d c5 ff
mov eax,__pthread_key_create
test rax,rax
jz .skip_mutex_init
call __pthread_init_some_mutex
.skip_mutex_init:
mov rax, 0xffffffffffffff60
sub rbx,r15
add QWORD PTR fs:[rax],rbx`