如何在GNU ARM程序集中不初始化内存?

时间:2019-04-04 02:29:03

标签: gcc assembly arm gnu-arm

我在Raspberry Pi上使用GCC来为我要学习的课程编译一些汇编代码。根据{{​​3}}中的信息,我可以在GNU ARM Assembly中重现以下C代码:

int num = 0;

写这篇文章:

        .data
num:    .word 0

太好了!现在我该怎么写?

int num;

据我了解,像这样保留未初始化的变量意味着我应该将其视为包含内存位置之前的任何垃圾值。因此,在以某种方式给它赋值之前,我不应该使用它。

但是假设出于某种原因,我打算在内存中存储大量数据,并且需要为其保留大量空间。在我看来,如果无论如何我都要用一些数据来填充整个内存区域,将其初始化为某个值会浪费大量资源。但是据我发现,如果不将其初始化为某个值,似乎无法在GCC ARM Assembly中创建标签。根据我的GNU Assembler Reference.word指令后面可以有零个表达式,但是如果使用这种方式,“那么地址计数器将不会前进,并且不会保留任何字节。”我的第一个方法是使用“ .space”或“ .skip”指令代替,但是对于该指令,甚至assembly textbook都说“如果省略逗号和填充,则假定填充为零。” < / p>

如果没有在GCC ARM Assembly中对其进行初始化,是否有办法保留一块内存?

2 个答案:

答案 0 :(得分:1)

通常,不需要初始化的数据应放在.bss部分。

    .bss
foobar:
    .skip 99999999

这将在.bss节中分配99999999字节,标签foobar将为其地址。它不会使您的目标文件或可执行文件增加99999999字节;可执行标头仅指示需要.bss的字节数,并且在加载时,系统会分配适当的数量并将其初始化为零。

您不能跳过加载时间零初始化。系统需要将其初始化为某种东西,因为否则它可能包含来自内核或其他进程的敏感数据。但是将内存清零非常快,内核将使用高效的算法,因此我不必担心性能影响。它的空闲时间甚至可能是零页,因此在程序加载时,已经有零个可用的内存。无论如何,您的程序在实际使用内存上所花费的时间将使它陷入瘫痪。

这意味着您还可以安全地将.bss用于确实要初始化为零的数据(尽管不要初始化为任何非零值;如果要int foo = 3;,则必须将其放入)在.data中,如您的原始示例一样。)

答案 1 :(得分:1)

尝试时发生了什么?

当我尝试时:

int num = 0;
int mun;

我得到了gnu

    .cpu arm7tdmi
    .eabi_attribute 20, 1
    .eabi_attribute 21, 1
    .eabi_attribute 23, 3
    .eabi_attribute 24, 1
    .eabi_attribute 25, 1
    .eabi_attribute 26, 1
    .eabi_attribute 30, 2
    .eabi_attribute 34, 0
    .eabi_attribute 18, 4
    .file   "so.c"
    .text
    .comm   mun,4,4
    .global num
    .bss
    .align  2
    .type   num, %object
    .size   num, 4
num:
    .space  4
    .ident  "GCC: (GNU) 8.3.0"
  

.comm符号,长度

     

.comm声明一个名为symbol的通用符号。   链接时,一个目标文件中的通用符号可以与   在另一个目标文件中定义的或具有相同名称的通用符号。如果   ld没有看到该符号的定义-只是一个或多个常见符号   符号-然后它将分配未初始化内存的长度字节。   长度必须是绝对表达式。如果ld看到多个共同点   具有相同名称的符号,并且它们的大小并不相同,   将使用最大尺寸分配空间。

     

使用ELF时,.comm指令采用可选的第三个参数。   这是符号的期望对齐方式,指定为字节   边界(例如,对齐16表示最小   地址的高4位应为零)。对齐方式必须   是绝对表达式,并且必须是2的幂。如果ld   为通用符号分配未初始化的内存,它将使用   放置符号时对齐。如果未指定对齐方式,则为   将对齐方式设置为小于或等于2的最大幂   符号的大小,最大为16。

     

.comm的语法在HPPA上略有不同。语法是   `symbol .comm,length';符号是可选的。

汇编语言是由汇编程序而非目标定义的。因此,答案将是特定于汇编器(读取和汇编汇编语言程序的工具),并且没有理由假定一个汇编器的答案与另一个汇编器的答案相同。以上是用于gnu汇编器的气体。

您可能已经看过参考的文档或阅读了其他gnu文档。但是,回答在已编译程序中执行此操作时发生的情况的最简单方法是仅对其进行编译并查看编译器的输出。

但是不一定要假设它没有初始化:

unsigned int num;
unsigned int fun ( void )
{
    return(num);
}

足以链接它:

Disassembly of section .text:

00001000 <fun>:
    1000:   e59f3004    ldr r3, [pc, #4]    ; 100c <fun+0xc>
    1004:   e5930000    ldr r0, [r3]
    1008:   e12fff1e    bx  lr
    100c:   00002000    andeq   r2, r0, r0

Disassembly of section .bss:

00002000 <__bss_start>:
    2000:   00000000

它最终在初始化的bss中结束。

您真的想要未初始化的访问权限,然后选择一个地址(您知道未初始化的地址(sram))并访问它:

ldr r0,=0x1234
ldr r0,[r0]