为什么没有特定的寄存器来访问寄存器的其他部分(16-32)?
像啊或al一样访问ax寄存器的8位部分.

我试图了解对象如何在汇编级别工作.对象如何存储在内存中,以及成员函数如何访问它们?
(编者注:原始版本过于宽泛,并且首先对装配和结构的工作方式产生了一些困惑.)
我们都知道,在查看源代码时,可以安全地假设方向标志清晰.方向标志的概率非常低.
我想了解其他旗帜的可能性.这就是为什么我编写了一个测试程序,它单步执行我现有的一些软件,为前12个EFLAGS位中的每一个增加一个计数器.
结果证实了关于方向标志(DF)的假设,并且毫不奇怪地表明溢出标志(OF)的概率非常低.
但其他旗帜怎么样?进位标志(CF),辅助标志(AF),零标志(ZF)和符号标志(SF)似乎稳定在25%,但奇偶校验标志(PF)跳出超过50%.
我想知道为什么CF,AF,ZF和SF的概率如此之低.
对于PF,我自己的两分钱解释告诉我,鉴于所有可能的8位位模式中的奇偶校验偶数和奇偶校验的50-50分布并且意识到一些最常用的数字(0和-1)具有甚至平价,超过50%的机会是合理的.
在Xeno Kovah在OpenSecurityTraining 上主持的x86 程序集介绍的第一天作业中,他指定:
我们现在知道的说明(24)
NOP PUSH/POP CALL/RET MOV/LEA ADD/SUB JMP/Jcc CMP/TEST AND/OR/XOR/NOT SHR/SHL IMUL/DIV REP STOS,REP MOV LEAVE
编写一个程序来查找我们尚未涵盖的指令,并在明天报告该指令。
他进一步断言这个任务是,
SAL/SAR MUL/IDIV变体IMUL/DIV也不要指望是否可以找到 GCC 当前输出的 x86 汇编指令列表,而不是objdump随机执行并审核它们然后创建源代码?
这个问题的基础似乎是实际使用的指令的一个非常小的子集,人们需要知道逆向工程(这是课程的重点)。Xeno 似乎试图找到一种有趣的、有指导意义的方式来说明这一点,
我认为知道大约 20-30(不包括变化)就足够了,你很少会检查手册
虽然我欢迎大家加入我在 OpenSecurityTraining 的这个很棒的课程,但问题是我提出的从 GCC 中找出它的方法(如果可能的话)。不是,让人们真正完成 Xeno 的任务。;)
我刚刚查看了彼得·科德斯(Peter Cordes)的回答,他说,
如果读取标志,则部分标志停顿会发生,如果它们确实发生的话。P4永远不会有部分标志停顿,因为它们永远不需要合并。相反,它具有错误的依赖关系。几个答案/评论混淆了术语。它们描述了一个错误的依赖关系,但随后将其称为部分标志停顿。这是由于仅写入一些标志而导致的速度下降,但是术语“部分标志停顿”是指必须合并部分标志写入时在SnB之前的Intel硬件上发生的情况。英特尔SnB系列CPU插入一个额外的uop来合并标志而不会停顿。Nehalem和更早的失速约7个周期。我不确定AMD CPU会受到多大的损失。
我感觉我还不明白什么是“部分国旗摊位”。我怎么知道一个人发生了?除了读取标志的某些时间之外,什么触发事件?合并标志是什么意思?在什么情况下会“写一些标志”,但不会发生部分标志合并?我需要了解哪些有关旗位的知识才能理解它们?
Haswell及更早版本的ADC通常为2 uops,有2个周期延迟,因为Intel uops传统上只能有2个输入(https://agner.org/optimize/).在Haswell为FMA引入3输入微指令和某些情况下的索引寻址模式的微融合之后,Broadwell/Skylake及其后来都有单uop ADC/SBB/CMOV .
(但不适用于adc al, imm8短格式编码,或其他al/ax/eax/rax,imm8/16/32/32短格式,没有ModRM.我的答案中有更详细的说明.)
但是adc,即时0是特殊的Haswell解码为只有一个uop. @BeeOnRope测试了这个,并在他的uarch-bench中包含了对这个性能怪癖的检查:https://github.com/travisdowns/uarch-bench.从输出样本CI一个的Haswell服务器上示出之间的差adc reg,0和adc reg,1或adc reg,zeroed-reg.
(对于SBB也是如此.就我所见,在任何CPU上具有相同立即数的等效编码,ADC和SBB性能之间从来没有任何差别.)
这个优化何时adc bl,0推出?
我测试了Core 2 1,发现imm=0延迟是2个周期,相同adc eax,0.同时,也是循环计数是与吞吐量测试一些变化相同的adc eax,3对比0,所以第一代的Core 2(Conroe处理器/ Merom处理器)并没有这样做优化.
回答这个问题的最简单方法可能是在Sandybridge系统上使用我的测试程序,看看是否3比它快adc eax,0.但基于可靠文档的答案也可以.
(顺便说一句,如果有人可以访问Sandybridge上的perf计数器,你还可以通过运行@ BeeOnRope的测试代码来清除在执行uop计数不是处理器宽度倍数的循环时性能降低的谜团.或者是性能我在不再工作的SnB上观察到的只是因为未分层与正常的uops有什么不同?)
脚注1:我在运行Linux的Core 2 E6600(Conroe/Merom)上使用了这个测试程序.
;; NASM / YASM
;; assemble / link this …Run Code Online (Sandbox Code Playgroud) 我正在查看汇编中的不同指令,我对如何决定不同操作数和操作码的长度感到困惑.
这是你应该从经验中得知的东西,还是有办法找出哪个操作数/运算符组合占用了多少字节?
例如:
push %ebp ; takes up one byte
mov %esp, %ebp ; takes up two bytes
Run Code Online (Sandbox Code Playgroud)
所以问题是:
在看到给定的指令后,如何推断出其操作码需要多少字节?
我开始学习汇编程序,这对我来说并不合乎逻辑.
为什么我不能在寄存器中使用多个更高的字节?
我理解rax- > eax- > 的历史原因ax,所以让我们关注新的 64位寄存器.例如,我可以使用r8和r8d,但为什么不r8dl和r8dh?同样适用于r8w和r8b.
我最初的想法是,我可以使用8个r8b在同一时间寄存器(就像我可以做的al,并ah在同一时间).但我不能.并且使用r8b使完整的r8寄存器"忙".
这提出了一个问题 - 为什么?如果您不能同时使用其他部件,为什么还只需要使用寄存器的一部分?为什么不保持只r8忘记下部?
首先我想谈一下我对此的一些理解,如有错误请指正。
MFENCE在x86中可以保证全屏障顺序一致性可防止 STORE-STORE、STORE-LOAD、LOAD-STORE 和 LOAD-LOAD 重新排序
这是根据维基百科的说法。
std::memory_order_seq_cst不保证防止 STORE-LOAD 重新排序。
这是根据Alex 的回答,“负载可能会通过早期存储重新排序到不同位置”(对于 x86),并且 mfence 不会总是被添加。
a是否std::memory_order_seq_cst表示顺序一致性?根据第2/3点,我认为这似乎不正确。std::memory_order_seq_cst仅当以下情况时才表示顺序一致性
MFENCE添加到任一LOAD或STORE否则仍有可能重新订购。
根据@LWimsey的评论,我在这里犯了一个错误,如果 和LOAD都是STORE,memory_order_seq_cst则没有重新排序。Alex 可能指出使用非原子或非 SC 的情况。
std::atomic_thread_fence(memory_order_seq_cst)总是产生一个完整的屏障
这是根据Alex的回答。所以我总是可以替换asm volatile("mfence" ::: "memory")为std::atomic_thread_fence(memory_order_seq_cst)
这对我来说很奇怪,因为memory_order_seq_cst原子函数和栅栏函数之间的用法似乎有很大不同。
现在我在MSVC 2015的标准库的头文件中找到这段代码,它实现了std::atomic_thread_fence
inline void _Atomic_thread_fence(memory_order _Order)
{ /* …Run Code Online (Sandbox Code Playgroud) x86 ×10
assembly ×9
c++ ×2
x86-64 ×2
64-bit ×1
code-size ×1
flags ×1
gcc ×1
instructions ×1
intel ×1
machine-code ×1
parity ×1
performance ×1
stdatomic ×1