lock xadd
遇到了一组指令,我猜想它来自一个C ++智能指针模板。 (自从我编写C ++以来已经很长时间了,所以我不确定是哪一个。)这种影响
ZF
,什么时候不使用jne
?因为edi
始终为0,所以这部分代码永远不会执行,因此我无法执行。更令人困惑的是,其中有两个并排。第一个在edi[1]
上运行,第二个在edi[2]
上调用vtable[1]
。#1 楼
我认为您的一般评论是相当正确的(尽管不确定智能指针)。作为xadd的提示:三脚架是一个不错的汇编程序参考,给出了全面的描述。作为加法,xadd影响零标志。锁前缀将其转换为原子指令。如果您的“智能指针”解释正确,则此锁将是保持引用计数整洁的必要条件。lea ecx,dword ptr ds:[edi+0x4] ; edi is a class object
or eax,0xFFFFFFFF
lock xadd dword ptr ds:[ecx],eax ; add -1 to edi[1], eax obtains edi[1]
jne sdk.1000C801 ; edi[1] != 1 ? yes -> sdk.1000c801
mov eax,dword ptr ds:[edi] ; edi's vtable
mov ecx,edi ; prepare thiscall
call dword ptr ds:[eax] ; call edi->vtable[0]
在伪代码中,您可以这样编写(寄存器值前面带有下划线):
int _eax = _edi[1];
if (_edi[1]-- != 1)
goto sdk.1000c801; //_eax has _edi[1] value, in case it's needed here
_edi->vtable[0] (); //call first entry in vtable
#2 楼
josh已充分回答了有关零标志和xadd
指令的问题。此答案旨在添加有关您看到的智能指针的一些周围信息。您所看到的是shared_ptr
的典型代码,shared_ptr
是C ++标准库中的标准引用计数智能指针。一个shared_ptr
对象(即指针本身,而不是它指向的对象!)包含两个(!)指针值。第一个指针指向对象,第二个指针指向管理对象。管理对象包含vtable指针,后跟两个引用计数,后跟其他东西,具体取决于管理对象的特定类型(例如,如果删除程序不是无状态的,则删除程序的状态也包含在管理对象中)。管理对象中的第一个引用计数包含对对象的强引用数(即,指向该对象的weak_ptr
的数量),而第二个引用计数包含对管理对象的引用数。所有强引用一起算作对管理对象的单个引用,但是每个shared_ptr
都算作对管理对象的单独的进一步引用。每当(非空)
delete
超出范围时,强引用的数量减少了。如果强引用的计数达到零,则pointee的生存期结束,并且调用第一个vtable函数以销毁pointee。这将在创建共享指针时调用指定的删除器(如果未指定删除器,则该共享指针(间接)默认为delete[]
(对于数组,可能默认为weak_ptr
)。此外,在删除对象后,所有强引用对管理对象的累积引用也会减少。如果该引用计数达到零,则可以通过调用第二个vtable函数销毁管理对象。当(非空)
weak_ptr
超出范围时,仅对管理对象的引用计数会减少(因为weak_ptr
没有强大的引用)。如果此引用计数达到零,则不存在强引用(因为否则将仍然存在对管理的累积引用),并且没有其他shared_ptr
。当最后一个强引用超出范围时,pointe已被破坏,因此仅破坏了管理对象(同样,通过调用第二个vtable条目)。Pointee和管理对象是同时创建的。在这种情况下,两个对象的内存可以在一个块中分配。在这种情况下,管理对象不大于vtable,并且两个引用计数并位于指针对象之前。第一个vfunction仅调用pointee的析构函数,但不释放其内存。第二个vfunction破坏包含管理对象和已破坏的pointe的内存块。使用
make_shared
创建shared_ptr
时会进行此优化。这种优化的缺点是,仅当不存在弱引用或强引用时才释放指向者的存储块,而不是仅在强引用消失时才释放。在weak_ptr
的大多数使用情况下,没有q4312079q,因此缺点通常并不重要。评论
感谢您的解释。您提到的内存布局完全符合我的需求。
–二十
18年8月31日在19:04
评论
因此,为了清楚起见,在未将add edi [1]与任何内容进行比较之后,它的值单独决定了零标志的状态吗?
–二十
18年8月31日在19:06
如果结果为零(则ZF = 1),则加法会将零标志设置为零。可能的后续比较将读取零标志并采取相应的措施。在ZF == 0的情况下,jne会跳到其目标,即,加法未得到零。它与jnz相同。比较(cmp)指令是两个操作数的减,而不修改其中一个操作数。从引用的网站引用:“比较是通过从第一个操作数中减去第二个操作数,然后以与SUB指令相同的方式设置状态标志来进行的。”
–乔什
18年8月31日在20:09