汇编代码 - 循环中的异或如何工作? [复制]
Posted
技术标签:
【中文标题】汇编代码 - 循环中的异或如何工作? [复制]【英文标题】:Assembly Code - How does xor in a loop works? [duplicate] 【发布时间】:2016-09-12 01:30:56 【问题描述】:我有这个汇编代码,其中有一个 for 循环,我将把它改回 C 代码。但是,我注意到循环中有一个异或。
.L3:
movq -8(%rbp), %rax
andl $1, %eax
xorl %eax, -12(%rbp)
sarq -8(%rbp)
.L2:
cmpq $0, -8(%rbp)
jg .L3
所以我知道一个 for 循环会不断循环,只要它大于 0 并且每个循环都除以 2。但是我遇到的问题是andl和xorl。我知道它用 and 检查 1 和 eax 并根据它们的值返回 1 或 0,但是循环如何更改 xor?
【问题讨论】:
logic gate AND/OR/XOR/NOT/... ... 等等 x86mov al,0b1010
xor al,0b0011
将导致 al
= 0b1001
。 ... and al,0b0011
而不是 xor 会产生 al
= 0b0010
。而or al,0b0011
将产生al
= 0b1011
。 not al
将以 al
= 0b11110101
结尾(在其他示例中我没有写那些较高的 4 位零,但在 not
之后它们也被反转了)(将值写在彼此上方以便更好地查看和比较它与“门”文章)
Eww,为什么所有的内存操作数?我没有看到 RBP 的指针增量发生,所以 IDK 为什么该代码不只是对所有内容使用寄存器。我假设来自gcc -O0
:(
【参考方案1】:
假设局部变量b
位于-8(%rbp)
,局部变量c
位于-12(%rbp)
。
.L3: movq -8(%rbp), %rax
andl $1, %eax
将eax
的值设置为b
的最低有效位的值。
xorl %eax, -12(%rbp)
与c
和b
的最低有效位执行异或,将结果存储在c
中。
sarq -8(%rbp)
将b
除以2
。
cmpq $0, -8(%rbp)
jg .L3
如果b
大于0
,则返回循环开始,否则继续。
所以对应的C代码是:
do
c ^= (b & 1);
b /= 2; // Or: b >>= 1;
while ( b > 0 );
虽然.L2
标签的存在表明之前可能有一个jmp .L2
,但您没有向我们展示,在这种情况下它将是一个while
循环:
while ( b > 0 )
c ^= (b & 1);
b /= 2; // Or: b >>= 1;
一个工作演示(在 OS X 上使用 gas 汇编器):
asm_func.S
:
.globl _asm_func
.text
_asm_func:
push %rbp
mov %rsp, %rbp
sub $16, %rsp
movq %rdi, -8(%rbp)
movl %esi, -12(%rbp)
jmp .L2
.L3:
movq -8(%rbp), %rax
andl $1, %eax
xorl %eax, -12(%rbp)
sarq -8(%rbp)
.L2:
cmpq $0, -8(%rbp)
jg .L3
movl -12(%rbp), %eax
leave
ret
main.c
:
#include <stdio.h>
int asm_func(int b, int c);
int c_func(int b, int c)
while ( b > 0 )
c ^= (b & 1);
b >>= 1;
return c;
int main(void)
for ( int i = 112; i < 127; i += 7 )
for ( int j = 203; j > 182; j -= 9 )
printf("C function (%d, %d): %d\n", i, j, c_func(i, j));
printf("Asm function(%d, %d): %d\n", i, j, asm_func(i, j));
return 0;
Makefile
:
prog: main.o asm_func.o
cc -o prog main.o asm_func.o
main.o: main.c
cc -o main.o main.c -c -std=c99 -pedantic -Wall -Wextra
asm_func.o: asm_func.S
as -o asm_func.o asm_func.S
带输出:
paul@horus:~/src/sandbox/so_asm$ ./prog
C function (112, 203): 202
Asm function(112, 203): 202
C function (112, 194): 195
Asm function(112, 194): 195
C function (112, 185): 184
Asm function(112, 185): 184
C function (119, 203): 203
Asm function(119, 203): 203
C function (119, 194): 194
Asm function(119, 194): 194
C function (119, 185): 185
Asm function(119, 185): 185
C function (126, 203): 203
Asm function(126, 203): 203
C function (126, 194): 194
Asm function(126, 194): 194
C function (126, 185): 185
Asm function(126, 185): 185
paul@horus:~/src/sandbox/so_asm$
【讨论】:
我被告知不要包含不必要的代码,所以我没有包含开头。但是是的,在 main 中有一个跳转到 L2 的调用。 b%1 是如何工作的?只比较最小的位?b & 1
只是一个常规的按位与。它评估为1
是b
是奇数,如果b
是偶数则评估为0
。
感谢您的示例!
@JMei:顺便说一句,这看起来像奇偶校验计算:所有位的水平异或。请参阅this Q&A,了解如何通过将上半部分和下半部分异或到一个字节来更有效地计算奇偶校验。重复到一位,或者只读取 PF,因为 x86 已经计算了奇偶校验。
哇,我刚刚注意到这个函数使用有符号整数比较。这太奇怪了,它会返回除设置了高位(符号位)的整数的奇偶校验之外的东西。我想知道在原始 C 源代码中是否有意使逆向工程变得更加棘手?以上是关于汇编代码 - 循环中的异或如何工作? [复制]的主要内容,如果未能解决你的问题,请参考以下文章