assembly 关于ARM汇编中全局变量的问题

jvidinwx  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(287)

我的书中描述了为ARM处理器编写程序时所发生的情况:

他们说文本段是机器代码,它还包含文字池,他们还说全局数据段包含全局变量。
但是在另一个例子中,我认为全局变量是使用文字池创建的,因此文字的值是全局变量的地址。
这两件事是否互相矛盾?(一个说全局变量在全局数据段中,另一个说我们在文本段中使用了文字池)或者我误解了什么?

7uzetpgm

7uzetpgm1#

你,程序员,最终决定内存如何分配,而不是工具,除了一些例外,肯定不是ARM。

unsigned int x;
unsigned int y=5;

void fun ( void )
{
    x=3;
    y++;
}

arm-none-eabi-gcc -O2 -c so.c -o so.o
arm-none-eabi-objdump -D so.o

so.o:     file format elf32-littlearm

Disassembly of section .text:

00000000 <fun>:
   0:   e3a00003    mov r0, #3
   4:   e59f2014    ldr r2, [pc, #20]   ; 20 <fun+0x20>
   8:   e5923000    ldr r3, [r2]
   c:   e59f1010    ldr r1, [pc, #16]   ; 24 <fun+0x24>
  10:   e2833001    add r3, r3, #1
  14:   e5823000    str r3, [r2]
  18:   e5810000    str r0, [r1]
  1c:   e12fff1e    bx  lr
    ...

Disassembly of section .data:

00000000 <y>:
   0:   00000005    andeq   r0, r0, r5

Disassembly of section .bss:

00000000 <x>:
   0:   00000000    andeq   r0, r0, r0

这是在对象级别上。
那么如果我们把

MEMORY
{
    one   : ORIGIN = 0x00000000, LENGTH = 0x1000
    two   : ORIGIN = 0x20000000, LENGTH = 0x1000
    three : ORIGIN = 0x20002000, LENGTH = 0x1000
}
SECTIONS
{
    .text   : { *(.text*)   } > one
    .rodata : { *(.rodata*) } > one
    .bss    : { *(.bss*)    } > two
    .data   : { *(.data*)   } > three
}

arm-none-eabi-ld -T flash.ld so.o -o so.elf
arm-none-eabi-objdump -D so.elf

so.elf:     file format elf32-littlearm

Disassembly of section .text:

00000000 <fun>:
   0:   e3a00003    mov r0, #3
   4:   e59f2014    ldr r2, [pc, #20]   ; 20 <fun+0x20>
   8:   e5923000    ldr r3, [r2]
   c:   e59f1010    ldr r1, [pc, #16]   ; 24 <fun+0x24>
  10:   e2833001    add r3, r3, #1
  14:   e5823000    str r3, [r2]
  18:   e5810000    str r0, [r1]
  1c:   e12fff1e    bx  lr
  20:   20002000    andcs   r2, r0, r0
  24:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <x>:
20000000:   00000000    andeq   r0, r0, r0

Disassembly of section .data:

20002000 <y>:
20002000:   00000005    andeq   r0, r0, r5

与您所看到的图片类似,.data和.bss是全局数据。.data正在初始化,而.bss正在未初始化。
这当然不是一个可用的二进制文件,没有异常表,没有引导程序,等等,但是这也表明了工具只是按照你告诉他们的去做,你最终要负责。
这里是游泳池

20:   20002000    andcs   r2, r0, r0
  24:   20000000    andcs   r0, r0, r0

我使用了反汇编器,所以它试图反汇编地址,忽略andcs的东西。你可以看到代码是如何生成的,以便稍后在链接过程中,链接器可以将代码连接到这些数据项所在的地址。
因此,正如问题下的注解所述,变量位于全局数据区,池指向它。池也可用于其他原因。任何时候代码都需要更多的“立即”类型数据。如果这是x86或其他一些可变长度指令,则这些类型的值可能是“指令”的一部分。如果你从它有自己的池的Angular 来看它,

unsigned int fun ( void )
{
    return(0x12345678);
}
00000000 <fun>:
   0:   e59f0000    ldr r0, [pc]    ; 8 <fun+0x8>
   4:   e12fff1e    bx  lr
   8:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

这个指令集不能有32位立即数,所以它可以用四条指令或两条更新的arm指令来构建,或者从池中加载。
为了证明这一点,这里并不是说x86很重要。
0000000000000000个:05 00 00 00 00 03移动$0x3,0x 0(%撕裂)# a〈乐趣+0xa〉7:00 00 00一:第11集:第11集c3重新请求
0000000000000000个:0:b8 78 56 34 12移动$0x12345678,%每个5:c3重新请求

Disassembly of section .text:

0000000000000000 <fun>:
   0:   c7 05 f6 ff ff 1f 03    movl   $0x3,0x1ffffff6(%rip)        # 20000000 <x>
   7:   00 00 00 
   a:   83 05 ef 1f 00 20 01    addl   $0x1,0x20001fef(%rip)        # 20002000 <y>
  11:   c3                      retq   

Disassembly of section .bss:

0000000020000000 <x>:
    20000000:   00 00                   add    %al,(%rax)
    ...

Disassembly of section .data:

0000000020002000 <y>:
    20002000:   05                      .byte 0x5
    20002001:   00 00                   add    %al,(%rax)
    ...

而且链接器修改指令本身而不是池区域。我确信有,而且我确信我也可以为x86生成一些池空间。
还要注意,在x86上使用的相同链接器脚本告诉x86我希望它做什么。
最终,您可以控制这一级别的内存消耗。有一些硬件规则,如芯片在哪里复位以及如何复位,在某些情况下(如cortex-m),一些内存块用于闪存/代码,一些用于数据,有些是用于外围设备的。你最终应该知道这一点,并相应地设计你的内存Map。大多数时候,人们只是从别人那里拿来为目标设置的工具,这一切都神奇地发生了。
就像当你在windows/linux/etc主机上使用编译器时,工具链被配置为为目标处理器和操作系统生成二进制代码。同样的源代码,在linux上编译,结果与在windows上编译不同,同样的工具链/版本,为不同的目标构建。

相关问题