我的书中描述了为ARM处理器编写程序时所发生的情况:
他们说文本段是机器代码,它还包含文字池,他们还说全局数据段包含全局变量。但是在另一个例子中,我认为全局变量是使用文字池创建的,因此文字的值是全局变量的地址。这两件事是否互相矛盾?(一个说全局变量在全局数据段中,另一个说我们在文本段中使用了文字池)或者我误解了什么?
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上编译不同,同样的工具链/版本,为不同的目标构建。
1条答案
按热度按时间7uzetpgm1#
你,程序员,最终决定内存如何分配,而不是工具,除了一些例外,肯定不是ARM。
这是在对象级别上。
那么如果我们把
与您所看到的图片类似,.data和.bss是全局数据。.data正在初始化,而.bss正在未初始化。
这当然不是一个可用的二进制文件,没有异常表,没有引导程序,等等,但是这也表明了工具只是按照你告诉他们的去做,你最终要负责。
这里是游泳池
我使用了反汇编器,所以它试图反汇编地址,忽略andcs的东西。你可以看到代码是如何生成的,以便稍后在链接过程中,链接器可以将代码连接到这些数据项所在的地址。
因此,正如问题下的注解所述,变量位于全局数据区,池指向它。池也可用于其他原因。任何时候代码都需要更多的“立即”类型数据。如果这是x86或其他一些可变长度指令,则这些类型的值可能是“指令”的一部分。如果你从它有自己的池的Angular 来看它,
这个指令集不能有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重新请求
而且链接器修改指令本身而不是池区域。我确信有,而且我确信我也可以为x86生成一些池空间。
还要注意,在x86上使用的相同链接器脚本告诉x86我希望它做什么。
最终,您可以控制这一级别的内存消耗。有一些硬件规则,如芯片在哪里复位以及如何复位,在某些情况下(如cortex-m),一些内存块用于闪存/代码,一些用于数据,有些是用于外围设备的。你最终应该知道这一点,并相应地设计你的内存Map。大多数时候,人们只是从别人那里拿来为目标设置的工具,这一切都神奇地发生了。
就像当你在windows/linux/etc主机上使用编译器时,工具链被配置为为目标处理器和操作系统生成二进制代码。同样的源代码,在linux上编译,结果与在windows上编译不同,同样的工具链/版本,为不同的目标构建。