1
1
您知道这可能是特定于实现的,但很可能只是在数据部分获得初始化数据。如果它是一个常量,它可能会进入文本部分。
每次输入函数的作用域时,必须初始化已初始化的自动变量。空间
不可以。如果静态变量被初始化为零或null,或者根本没有初始化,那么它通常只足以在bss中保留空间。如果一个静态非常量变量被初始化为非零值,它将被放入数据段中。 |
2
1
正如@goodvibration正确指出的那样,只有全局或静态变量进入段。这是因为它们的生命周期是程序的整个执行时间。 局部变量具有不同的生存期。它们仅在其定义的块(如函数)执行期间存在。如果调用某个函数,所有不适合寄存器a的参数将被推送到堆栈,返回地址将写入链接寄存器。*该函数可能会在堆栈中保存链接寄存器和其他寄存器 并在堆栈中为本地 变量(这是您观察到的代码)。函数结束时,弹出保存的寄存器,并重新调整堆栈指针。这样,您就可以 自动垃圾收集 对于局部变量。 *:请注意,这仅适用于ARM的(某些调用约定)。这是不同的,例如英特尔处理器。 |
3
1
这是一个尝试一下的东西。
没有优化的第一件事。
不要担心警告,需要链接才能看到所有东西都找到了家
作为反汇编,它尝试反汇编数据,以便忽略(例如0x2008旁边的andeq)。 a变量是全局变量,未初始化,因此它会进入。bss(通常……编译器可以选择做任何它想做的事情,只要它正确地实现了语言,不必有所谓的东西。例如,bss,但gnu和其他许多编译器都有)。 b是全局的,并已初始化,因此它将进入。数据,如果它被声明为const,它可能会降落在其中。rodata取决于编译器及其提供的内容。 c是一个初始化的局部非静态变量,因为c提供递归,这需要在堆栈上(或使用寄存器或其他易失性资源管理),并在每次运行时初始化。我们需要在不进行优化的情况下进行编译才能看到这一点
d是我所说的局部全局,它是一个静态的局部,所以它位于函数之外,不在堆栈上,与全局一起,但只具有局部访问权限。 我在您的示例中添加了e,这是一个未初始化但随后使用的本地。如果我没有使用它,也没有进行优化,可能会为它分配空间,但没有初始化。 在堆栈上保存x(根据x在r0中输入的调用约定)
然后从堆栈中加载x,添加两个,在堆栈上另存为e。从读取e 此调用约定的堆栈和放置在返回位置,即r0。
对于所有体系结构,未优化这有点典型,总是从堆栈中读取变量并快速将其放回。对于传入参数和传出返回值所在的位置,其他体系结构有不同的调用约定。 如果我选择大小(-gcc线上的O2)
b是全局的,因此在对象级别必须为其保留一个全局空间。数据、优化并没有改变这一点。 a也是全球性的,也是静止的。bss,因为在对象级别,它被声明为这样分配的,以防另一个对象需要它。链接器不会删除这些。 现在c和d都是死代码,它们什么都不做,不需要存储,所以 c不再在堆栈上分配空间,d也不再分配任何空间。数据 空间 对于这个代码的调用约定,我们为这个体系结构提供了大量的寄存器,因此e不需要在 堆栈,它在r0中出现。可以用r0进行数学运算,然后在r0中返回。 我知道我没有告诉链接器放在哪里。bss通过告诉它。它输入的数据。bss位于同一空间,无投诉。例如,我可以把-Tbss=0x3000作为自己的空间,或者只是编写一个链接器脚本。链接器脚本可能会破坏典型的结果,所以要小心。 典型,但可能有一个编译器有例外: 非常量全局变量进入。数据或。bss取决于它们是否在声明期间初始化。 如果是常量,那么可能是。rodata或。取决于文本(或。数据或。bss技术上可行) 非静态局部变量根据需要放入通用寄存器或堆栈中(如果没有完全优化)。 静态局部变量(如果没有优化掉的话)与全局变量共存,但不能全局访问,它们只会得到分配的空间。数据或。bss和globals一样。 参数完全由编译器为该目标使用的调用约定控制。仅仅因为arm或mips或其他可能已经写下了一个约定,并不意味着编译器必须使用它,只有当他们声称支持某个约定或标准时,才应该尝试遵守。为了使编译器有用,它需要一个约定并坚持它,无论它是什么,以便函数的调用者和被调用者都知道从哪里获取参数和返回值。具有足够寄存器的体系结构通常会有一个约定,即为前这么多参数(不一定是一对一)使用少量寄存器,然后堆栈用于所有其他参数。同样,如果可能,可以使用寄存器作为返回值。一些架构由于缺少gprs或其他,在两个方向上都使用堆栈。或者其中一个是堆栈,另一个是寄存器。欢迎您找出约定并尝试阅读它们,但在一天结束时,您使用的编译器(如果没有破坏)遵循约定,通过设置类似于上面的实验,您可以看到约定在起作用。 此外,在这种情况下还进行了优化。
如果我告诉您arm约定通常使用r0-r3作为前几个参数,那么您可能会假设x在r0中,r1和r2用于y,我们可以在需要堆栈之前使用另一个小参数,好吧 可能是旧的arm,但现在它希望64位变量使用偶数,然后使用奇数。
因此r0包含x,r2/r3包含y,r1被传递。 这个测试是为了不让y成为死代码,并将其传递给另一个函数,我们可以看到y在进入fun和退出more\u fun的过程中存储在哪里。r2/r3即将进入,需要在r0/r1中调用更多乐趣。 我们需要保留x,以便从乐趣中回归。有人可能会认为x会落在堆栈上,而堆栈没有进行优化,但会保存一个寄存器,按照约定,该寄存器将由函数(r4)保存,并在整个函数中使用r4,或者至少在该函数中使用r4来存储x。如果x需要多次接触,则性能优化会比寄存器访问成本更高。 然后计算返回值并清理堆栈、寄存器。 在我看来,重要的是要看到这一点,调用约定对一些变量起作用,而其他变量可以根据优化而变化,没有优化,大多数人都会立即声明。bss。数据(.text/.rodata),然后进行优化,这取决于变量是否存在。 |
Community wiki · C中有哪些耗时的操作? 1 年前 |
Community wiki · 将所有处理器电源都投入到任务中 1 年前 |
Community wiki · C++为C添加了什么?[已关闭] 1 年前 |
Community wiki · 打印1到1000,不带循环或条件 1 年前 |