- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有以下 C 代码段:
int main() {
int tablica [100];
bool visited [100];
int counter;
int i;
for(i=0;i<=99;i++) {
if (visited[i]==0) {
counter=counter+1;
}
}
}
; ...
mov eax, DWORD PTR [rbp-8]
cdqe
movzx eax, BYTE PTR [rbp-528+rax]
xor eax, 1
test al, al
je .L3
; ...
CDQE
和
MOVZX
指令的含义和目的是什么吗?我也不明白
XOR
指令的用途是什么。
最佳答案
CDQE
指令将 EAX
寄存器中的 DWORD(32 位值)符号扩展为 RAX
寄存器中的 QWORD(64 位值)。MOVZX
指令将源零扩展到目标。在这种情况下,它将在 [rbp-528+rax]
处从内存加载的 BYTE 符号扩展到 DWORD 目标寄存器 EAX
。XOR eax, 1
指令只是翻转 EAX
的最低位。如果当前设置为 (1),则清除 (0)。如果当前清零 (0),则它变为设置 (1)。
什么是大局?好吧,事实证明,这几乎是完全没有意义的代码,您从未启用优化的编译器获得的那种输出。尝试和分析它没有什么意义。
但是,如果您愿意,我们无论如何都可以对其进行分析。这是您的 C 代码的整个汇编输出,由 GCC 8.2 在 -O0
生成,每条指令都带有注释:
main():
push rbp ; \ standard function
mov rbp, rsp ; / prologue code
sub rsp, 408 ; allocate space for stack array
mov DWORD PTR [rbp-8], 0 ; i = 0
.L4:
cmp DWORD PTR [rbp-8], 99 ; is i <= 99?
jg .L2 ; jump to L2 if i > 99; otherwise fall through
mov eax, DWORD PTR [rbp-8] ; EAX = i
cdqe ; RAX = i
movzx eax, BYTE PTR [rbp-528+rax] ; EAX = visited[i]
xor eax, 1 ; flip low-order bit of EAX (EAX ^= 1)
test al, al ; test if low-order bit is set?
je .L3 ; jump to L3 if low-order bit is clear (== 0)
; (which means it was originally set (== 1),
; which means visited[i] != 0)
; otherwise (visited[i] == 0), fall through
add DWORD PTR [rbp-4], 1 ; counter += 1
.L3:
add DWORD PTR [rbp-8], 1 ; i += 1
jmp .L4 ; unconditionally jump to top of loop (L4)
.L2:
mov eax, 0 ; EAX = 0 (EAX is result of main function)
leave ; function epilogue
ret ; return
i
和
counter
这样的值,它们是存储在寄存器中的主要目标),并且它有很多毫无意义的指令。
main():
xor eax, eax ; main will return 0
ret
int counter;
/* ... */
counter=counter+1;
counter
,但随后您尝试从中读取。由于它是一个具有自动存储期的变量,它的内容不会被自动初始化,读取一个未初始化的变量是未定义的行为。这证明了 C 编译器可以发出它想要的任何汇编代码。
counter
被初始化为 0,我们要手工编写这个汇编代码,忽略消除整个困惑的可能性。我们会得到类似的东西:
main():
mov edx, OFFSET visited ; EDX = &visited[0]
xor eax, eax ; EAX = 0
MainLoop:
cmp BYTE PTR [rdx], 1 ; \ EAX += (*RDX == 0) ? 1
adc eax, 0 ; / : 0
inc rdx ; RDX += 1
cmp rdx, OFFSET visited + 100 ; is *RDX == &visited[100]?
jne MainLoop ; if not, keep looping; otherwise, done
ret ; return, with result in EAX
EAX
总是保存返回值,所以我把
counter
放在
EAX
中,并假设我们从函数中返回
counter
。
RDX
是跟踪
visited
数组中当前位置的指针。它在整个
MainLoop
中增加 1(一个 BYTE 的大小)。考虑到这一点,除了
ADC
指令外,其余代码应该很简单。
if
。
ADC
执行以下操作:
destination = (destination + source + CF)
CF
是进位标志。
CMP
指令在它设置进位标志之前,如果
visited[i] == 0
,并且源是
0
,所以它只是我在指令右侧评论的内容:如果
EAX
(
counter
),它将
*RDX == 0
(
visited[i] == 0
) 加 1 ;否则,它会添加 0(这是一个无操作)。
main():
mov edx, OFFSET visited ; EDX = &visited[0]
xor eax, eax ; EAX = 0
MainLoop:
cmp BYTE PTR [rdx], 0 ; (*RDX == 0)?
jne Skip ; if not, branch to Skip; if so, fall through
inc eax ; EAX += 1
Skip:
inc rdx ; RDX += 1
cmp rdx, OFFSET visited + 100 ; is *RDX == &visited[100]?
jne MainLoop ; if not, keep looping; otherwise, done
ret ; return, with result in EAX
visited
数组的值的可预测性,可能是
slower due to branch prediction failure 。
关于assembly - C 编译器输出的此代码中的 MOVZX、CDQE 指令的含义/用途是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54618685/
MOVZX r32, r/m16 和 MOVZX r64, r/m16 都有操作码 0F B7,但后者有一个 REX.W 前缀。是什么让这两个指令不同?无论如何,它们都不应该将目标操作数的高 32 位
我正在尝试找到一条可以替换 MOVZX 的指令,因为我使用的是 EMU8086(它模拟不支持 MOVZX 的 8086)。 我发现的最接近的指令是CBW,它将值放入寄存器AX中,但它仅适用于带符号的值
我有以下 C 代码段: int main() { int tablica [100]; bool visited [100]; int counter; int i;
对于 asm 模拟器,我正在尝试编写将 ASM 代码转换为等效工作代码的工作代码。最好的代码是可以在一行或最多两到三行中完成的代码,不在乎关于速度。 根据我的理解。如果用 C++ 完成,MOVZX 将
我有一些未知的 C++ 代码是在发布版本中编译的,因此对其进行了优化。我正在努力解决的问题是: xor al, al add esp, 8 cmp byte ptr [ebp+
我是一名优秀的程序员,十分优秀!