gpt4 book ai didi

使用 AND、OR、SHR 和 SHL 指令以及数组将循环从 x86 汇编语言转换为 C 语言

转载 作者:行者123 更新时间:2023-12-01 23:12:43 33 4
gpt4 key购买 nike

我不明白问题出在哪里,因为结果是正确的,但其中有问题,我不明白。

1.这是我必须转换为 C 的 x86 代码:

%include "io.inc"  
SECTION .data
mask DD 0xffff, 0xff00ff, 0xf0f0f0f, 0x33333333, 0x55555555

SECTION .text
GLOBAL CMAIN
CMAIN:
GET_UDEC 4, EAX
MOV EBX, mask
ADD EBX, 16
MOV ECX, 1
.L:
MOV ESI, DWORD [EBX]
MOV EDI, ESI
NOT EDI
MOV EDX, EAX
AND EAX, ESI
AND EDX, EDI
SHL EAX, CL
SHR EDX, CL
OR EAX, EDX
SHL ECX, 1
SUB EBX, 4
CMP EBX, mask - 4
JNE .L

PRINT_UDEC 4, EAX
NEWLINE
XOR EAX, EAX
RET

2.我转换后的C代码,当我输入0时,它输出正确的答案,但我的代码中有一些错误的东西,我不明白是什么:

#include "stdio.h"
int main(void)
{
int mask [5] = {0xffff, 0xff00ff, 0xf0f0f0f, 0x33333333, 0x55555555};


int eax;
int esi;
int ebx;
int edi;
int edx;
char cl = 0;
scanf("%d",&eax);
ebx = mask[4];
ebx = ebx + 16;
int ecx = 1;
L:
esi = ebx;
edi = esi;
edi = !edi;
edx = eax;
eax = eax && esi;
edx = edx && edi;
eax = eax << cl;
edx = edx >> cl ;
eax = eax || edx;
ecx = ecx << 1;
ebx = ebx - 4;

if(ebx == mask[1]) //mask - 4
{
goto L;
}

printf("%d",eax);
return 0;
}

最佳答案

汇编 AND 是 C 按位​​ & ,不合逻辑&& 。 (与 OR 相同)。所以你想要eax &= esi .

(使用 &= “复合赋值”使 C 甚至看起来像 x86 风格的 2 操作数汇编,所以我建议这样做。)

NOT 也是按位翻转所有位,而不是 bool 化为 0/1。在 C 语言中是 edi = ~edi;

阅读 x86 指令的手册,如 https://www.felixcloutier.com/x86/not ,对于 C 运算符,如 ~!检查它们是否是您想要的。 https://en.cppreference.com/w/c/language/expressions https://en.cppreference.com/w/c/language/operator_arithmetic

您应该在调试器中单步执行 C 和 asm,以便注意到第一个分歧,并知道要修复哪个指令/C 语句。不要只运行整个过程并查看一个数字的结果!调试器对于 asm 非常有用;没有一个就不要浪费时间。


CL是ECX的低字节,不是单独的C变量。您可以在 uint32_t 之间使用并集和uint8_t在 C 中,或者只使用 eax <<= ecx&31; 因为你没有任何东西可以将 CL 与 ECX 分开写入。 (x86 移位掩盖了它们的计数;该 C 语句可以编译为 shl eax, clhttps://www.felixcloutier.com/x86/sal:sar:shl:shr )。 ECX的低5位也是CL的低5位。

SHR是逻辑右移,而不是算术右移,因此您需要使用 unsigned不是int至少对于>> 。但实际上只是将它用于所有用途。


您处理 EBX 的方式完全错误;它是一个指针。

 MOV             EBX, mask
ADD EBX, 16

这就像 unsigned int *ebx = mask+4;

双字的大小为 4 个字节,但 C 指针数学按类型大小缩放,因此 +1是一个完整的元素,而不是 1 个字节。所以 16 个字节是 4 个双字 = 4 unsigned int元素。

MOV             ESI, DWORD [EBX]

这是使用 EBX 作为地址的负载。如果您在调试器中单步执行 asm,这应该很容易看出:它不仅仅是复制值。

CMP             EBX, mask - 4
JNE .L

这是 NASM 语法;它与数组开始之前的双字的地址进行比较。它实际上是相当正常的 do{}while 循环的底部。 (Why are loops always compiled into "do...while" style (tail jump)?)

do {          // .L
...
} while(ebx != &mask[-1]); // cmp/jne

它从 mask 的末尾开始循环数组,当指针越过末尾时停止。

同样,比较可以是 ebx !-= mask - 1 。我用一元 & 写的(address-of) 取消[]以明确它是数组之前的一个元素的地址。

请注意,它的跳跃相等;你有你的if()goto倒退,只在平等上跳跃。这是一个循环。


unsigned mask[]应该是static因为它在 section .data ,不在堆栈上。而不是const ,因为它又在 .data 中不是.rodata (Linux) 或 .rdata (Windows))

这个不影响逻辑,只影响反编译的细节。


可能还有其他错误;我没有尝试检查所有内容。

关于使用 AND、OR、SHR 和 SHL 指令以及数组将循环从 x86 汇编语言转换为 C 语言,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61163354/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com