Assembly 汇编代码-循环中的xor如何工作?

Assembly 汇编代码-循环中的xor如何工作?,assembly,reverse-engineering,Assembly,Reverse Engineering,我有一个汇编代码,其中有一个for循环,我要把它改回C代码。但是,我注意到循环中有一个xor .L3: movq -8(%rbp), %rax andl $1, %eax xorl %eax, -12(%rbp) sarq -8(%rbp) .L2: cmpq $0, -8(%rbp) jg .L3

我有一个汇编代码,其中有一个for循环,我要把它改回C代码。但是,我注意到循环中有一个xor

.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。但我遇到的麻烦是安德尔和克索尔。我知道它用and检查1和eax,并根据它们的值返回1或0,但循环如何更改xor?

假设局部变量
b
位于
-8(%rbp)
,局部变量
c
位于
-12(%rbp)

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 assembler):

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;
}
输出:

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$ 

假设局部变量
b
位于
-8(%rbp)
,局部变量
c
位于
-12(%rbp)

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 assembler):

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;
}
输出:

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$ 

我被告知不要包含不必要的代码,所以我没有包含开头。但是,是的,有一个呼叫跳转到L2在主要。b%1是如何工作的?只需比较最小的位?
b&1
只是一个规则的按位AND。它的计算结果为
1
is
b
为奇数,如果
b
为偶数,则计算结果为
0
。谢谢您的示例@JMei:顺便说一句,这看起来像一个奇偶校验计算:所有位的水平异或。请参阅,了解如何通过将上半部分和下半部分XORing到一个字节来更有效地计算奇偶校验。重复一位,或者只读取PF,因为x86已经计算奇偶校验。哇,我刚刚注意到这个函数使用有符号整数比较。这太奇怪了,它返回的不是高位(符号位)整数的奇偶校验。我想知道在最初的C源代码中,这是否是有意的,以使反向工程变得更加棘手?我被告知不要包含不必要的代码,所以我没有包含开头。但是,是的,有一个呼叫跳转到L2在主要。b%1是如何工作的?只需比较最小的位?
b&1
只是一个规则的按位AND。它的计算结果为
1
is
b
为奇数,如果
b
为偶数,则计算结果为
0
。谢谢您的示例@JMei:顺便说一句,这看起来像一个奇偶校验计算:所有位的水平异或。请参阅,了解如何通过将上半部分和下半部分XORing到一个字节来更有效地计算奇偶校验。重复一位,或者只读取PF,因为x86已经计算奇偶校验。哇,我刚刚注意到这个函数使用有符号整数比较。这太奇怪了,它返回的不是高位(符号位)整数的奇偶校验。我想知道这是否是在原始C源代码中故意的,以使反向工程变得更加棘手。。。因此,在x86
mov-al上,0b1010
xor-al,0b0011
将导致
al
=
0b1001
和al,0b0011
代替xor将生成
al
=
0b0010
。而
或al,0b0011
将产生
al
=
0b1011
not al
将以
al
=
0b11110101
结尾(在其他示例中,我没有写那些更高的4位零,但在
not
之后,它们也是反转的)(为了更好地查看,将值写在彼此的上方,并将其与“gate”文章进行比较)Eww,为什么所有内存操作数?我没有看到RBP的指针增量发生,所以IDK解释为什么代码不只是对所有内容使用寄存器。我假设它来自
gcc-O0
:(…因此在x86
mov al上,0b1010
xor al,0b0011
将导致
al
=
0b1001
和al上,0b0011
代替xor将产生
al
0b0010
。而
或al,0b0011
将产生
al
而非al
将以
结束e> al
=
0b11110101
(在其他示例中,我没有写那些更高的4位零,但在
not
之后,它们也被颠倒了)(为了更好地查看,将值写在彼此上方,并与“gate”文章进行比较)Eww,为什么所有的内存操作数?我看不到RBP的指针增量发生,所以IDK为什么该代码不只是对所有内容使用寄存器。我假设它来自
gcc-O0
:(