gpt4 book ai didi

c - 将 O2 优化的 for 循环从汇编翻译成 C

转载 作者:太空宇宙 更新时间:2023-11-04 02:40:20 26 4
gpt4 key购买 nike

这是一道作业题。我试图从以下汇编代码(x86 linux 机器,使用 gcc -O2 优化编译)获取信息。我对每个部分都做了评论,以展示我所知道的。我的大部分假设可能是错误的,但我已经做了足够多的搜索,以至于我知道我应该在这里问这些问题。

.section        .rodata.str1.1,"aMS",@progbits,1

.LC0:
.string "result %lx\n" //Printed string at end of program
.text

main:
.LFB13:
xorl %esi, %esi // value of esi = 0; x
movl $1, %ecx // value of ecx = 1; result
xorl %edx, %edx // value of edx = 0; Loop increment variable (possibly mask?)
.L2:
movq %rcx, %rax // value of rax = 1; ?
addl $1, %edx // value of edx = 1; Increment loop by one;
salq $3, %rcx // value of rcx = 8; Shift left rcx;
andl $3735928559, %eax // value of eax = 1; Value AND 1 = 1;
orq %rax, %rsi // value of rsi = 1; 1 OR 0 = 1;
cmpl $22, %edx // edx != 22
jne .L2 // if true, go back to .L2 (loop again)
movl $.LC0, %edi // Point to string
xorl %eax, %eax // value of eax = 0;
jmp printf // print
.LFE13: ret // return

我应该把它变成下面填空的C代码

#include <stdio.h>
int main()
{
long x = 0x________;
long result = ______;
long mask;
for (mask = _________; mask _______; mask = ________) {
result |= ________;
}
printf("result %lx\n",result);
}

我有几个问题和健全性检查,我想确保我做对了,因为我发现的类似示例都不是针对优化代码的。在我自己编译一些试验时,我得到了一些接近的东西,但 L2 的中间部分总是关闭。

我的理解

开始时,esi 与自身进行异或,结果为 0,用 x 表示。然后将 1 添加到 ecx,这将由变量 result 表示。

x = 0;     result = 1;

然后,我相信循环增量变量存储在 edx 中并设置为 0。这将在 for 循环的第三部分(更新表达式)中使用。我还认为这个变量必须是掩码,因为稍后将 1 添加到 edx,表示循环增量(掩码 = mask++),以及在 for 循环的中间部分比较 edx(测试表达式又名掩码!= 22 ).

mask = 0; (in a way)

然后进入循环,rax 被设置为 1。我根本不明白它用在什么地方,因为我没有声明第四个变量,尽管它稍后显示为被安定并归零。

movq %rcx, %rax;

然后循环变量加一

addl $1, %edx;

下一部分对我来说意义不大

我觉得接下来的三个操作构成了循环的主体表达式,但是我不知道如何处理它们。它会导致类似于 result |= x ... 但我不知道还有什么

salq    $3, %rcx      
andl $3735928559, %eax
orq %rax, %rsi

其余的我觉得我掌握得很好。进行比较(如果 mask != 22,再次循环),并打印结果。

我遇到的问题我不明白几件事。

1) 我不明白如何计算变量。在程序集(rax、rcx、rdx、rsi)中似乎有 3 个硬编码以及一个增量或临时存储变量。我认为 rsi 将是 x ,而 rcx 将是 result,但我不确定 mask 是 rdx 还是 rax,无论哪种方式,最后一个变量是什么是吗?

2) 我不确定的 3 个表达式的作用是什么?我觉得我以某种方式将它们与增量混淆了,但是在不知道变量的情况下我不知道如何解决这个问题。

任何和所有的帮助都会很棒,谢谢!

最佳答案

答案是:

#include <stdio.h>
int main()
{
long x = 0xDEADBEEF;
long result = 0;
long mask;
for (mask = 1; mask != 0; mask = mask << 3) {
result |= mask & x;
}
printf("result %lx\n",result);
}

在程序集中:

rsiresult .我们推断这是因为它是获得 OR 的唯一值ed,它是 printf 的第二个参数(在 x64 linux 中,参数按顺序存储在 rdirsirdx 和其他一些目录中)。

x是一个常量,设置为 0xDEADBEEF .这肯定不能推导,但它是有道理的,因为它似乎在 C 代码中被设置为常量,之后似乎没有被设置。

现在剩下的,它被 GCC 的反优化混淆了。你看,GCC 检测到循环将执行 21 次,并且认为破坏条件并用无用的计数器替换它是聪明的。知道了,我们看到了edx是无用的计数器,rcxmask .然后我们可以推断出真实情况和真正的“增量”操作。我们可以看到 <<= 3在程序集中,注意如果你将一个 64 位 int 左移 22 次,它会变成 0(shift 3, 22 次意味着移动 66 位,所以它全部被移出)。

遗憾的是,这种反优化对于 GCC 来说非常普遍。该程序集可以替换为:

.LFB13: 
xorl %esi, %esi
movl $1, %ecx
.L2:
movq %rcx, %rax
andl $3735928559, %eax
orq %rax, %rsi
salq $3, %rcx // implicit test for 0
jne .L2
movl $.LC0, %edi
xorl %eax, %eax
jmp printf

它做的事情完全一样,但我们删除了无用的计数器并保存了 3 条汇编指令。它还能更好地匹配 C 代码。

关于c - 将 O2 优化的 for 循环从汇编翻译成 C,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32647068/

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