Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Gcc 为什么用这个简单的代码生成这么多LDR和STR指令?_Gcc_Assembly_Arm_Compiler Optimization_Cortex M - Fatal编程技术网

Gcc 为什么用这个简单的代码生成这么多LDR和STR指令?

Gcc 为什么用这个简单的代码生成这么多LDR和STR指令?,gcc,assembly,arm,compiler-optimization,cortex-m,Gcc,Assembly,Arm,Compiler Optimization,Cortex M,我有一个简单的C程序: int main(){ unsigned int counter = 0; ++counter; ++counter; ++counter; return 0; } 我正在使用以下编译标志: arm-none-eabi-gcc -c -mcpu=cortex-m4 -march=armv7e-m -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -DPART_TM4C123GH6PM

我有一个简单的C程序:

int main(){    
    unsigned int counter = 0;
    ++counter;
    ++counter;
    ++counter;
    return 0;
}
我正在使用以下编译标志:

arm-none-eabi-gcc -c -mcpu=cortex-m4 -march=armv7e-m -mthumb 
-mfloat-abi=hard -mfpu=fpv4-sp-d16 -DPART_TM4C123GH6PM -O0 
-ffunction-sections -fdata-sections -g -gdwarf-3 -gstrict-dwarf 
-Wall -MD -std=c99 -c -MMD -MP -MF"main.d" -MT"main.o" -o"main.o"  "../main.c"
(为了简洁起见,删除了一些-I指令)

请注意,我故意使用
-O0
禁用优化,因为我想了解编译器如何优化

这将编译为ARM Cortex-M4的以下部件:

6           unsigned int counter = 0;
00000396:   2300                movs       r3, #0
00000398:   607B                str        r3, [r7, #4]
7           ++counter;
0000039a:   687B                ldr        r3, [r7, #4]
0000039c:   3301                adds       r3, #1
0000039e:   607B                str        r3, [r7, #4]
8           ++counter;
000003a0:   687B                ldr        r3, [r7, #4]
000003a2:   3301                adds       r3, #1
000003a4:   607B                str        r3, [r7, #4]
9           ++counter;
000003a6:   687B                ldr        r3, [r7, #4]
000003a8:   3301                adds       r3, #1
000003aa:   607B                str        r3, [r7, #4]

为什么生成了这么多
ldr3、[r7,#4]
strr3、[r7,#4]
指令?为什么
r7
甚至需要参与,难道我们不能只使用
r3

而不进行优化(这显然是),编译器必须做的就是发出指令,导致更高级语言定义的行为。它可以完全孤立地天真地对待每一项声明,而这正是它在这里所做的;从编译器的角度来看:

  • 一个变量声明:那么,我需要一个存储它的地方,我可以通过创建一个堆栈帧来实现这一点(未显示,但是
    r7
    在这里被用作帧指针)
  • 新语句:
    计数器=0-好的,我记得
    计数器
    的存储在本地堆栈帧中,所以我只需选择一个暂存寄存器,生成值0并将其存储到该位置,作业完成
  • 新语句:
    ++计数器
    -就在那时,我记得
    计数器的存储在本地堆栈帧中,所以我选择一个暂存寄存器,用变量的值加载它,增加它,然后通过存储结果来更新变量的值。返回值未使用,因此请忽略它。工作完成了
  • 新语句:
    ++计数器
    -就在那时,我记得
    计数器的存储在本地堆栈帧中,所以我选择一个暂存寄存器,用变量的值加载它,增加它,然后通过存储结果来更新变量的值。返回值未使用,因此请忽略它。工作完成了。因为我是一个软件的一部分,我甚至不能理解人类对似曾相识的概念,更不用说体验它了
  • 新语句:
    ++计数器-那就

等等。每一条语句,完美地编译成机器指令,做正确的事情。正是你让我做的。如果您想让我在更高的层次上对代码进行推理,并确定我是否可以利用这些语句之间的关系,那么您应该说点什么…

如果计数器变量未声明为volatile,并且如果您为size(-Os参数)设置了优化,gcc将使用 movs rn,#3
str rn,[变量地址]

您忘记启用优化了吗?您也没有说您正在使用的编译器。r7显然被用作局部变量的基址,在本例中,r7+4是计数器的地址。如前所述,似乎未启用优化。优化编译器可能会检测到计数器从未在main之外使用,并完全忽略它,因此main()只会变成一个返回值0。你完全正确,如果我使用
-O1
,那么所有指令都会被删除,函数返回0。
-O0
会在每个语句后将所有内容溢出到内存中,因此,您可以在调试器中更改任何内容,它将产生“预期”效果。这就是为什么
-O0
代码是如此嘈杂和可怕,作为人类阅读。它不仅仅是“未优化”,它还反映了更多关于gcc内部的信息,而不是简单的由人直接翻译成asm的内容。实际上,您应该编写函数,获取参数并返回结果,这样它们就不会在
-O3
上进行优化。执行此操作可获得格式良好的asm,并在编辑后自动重新编译。(不幸的是,Matt安装的最新ARM编译器仅为g++4.8,但对于C++11 std::atomic来说,如果您想在启用优化的情况下强制内存访问,这仍然足够新。)或者换句话说,实际上,禁用了优化(默认的
-O0
)=gcc/clang的调试模式,因此,他们有意将每个C语句编译成单独的asm块。这允许GDB使用
jump
命令跳转到其他源代码行,让一切都像在C抽象机器中跳转一样工作
-O0
不仅仅是试图优化,它还需要进行反优化,就像一切都是不稳定的一样。