gpt4 book ai didi

assembly - 什么是可重定位和绝对机器代码?

转载 作者:行者123 更新时间:2023-12-02 10:11:38 24 4
gpt4 key购买 nike

在学习汇编程序时,我遇到了这些术语。我的想法是这样的,在可重定位的机器代码中,代码不依赖于静态RAM位置。汇编程序为我的程序指定RAM需求。可以在链接器为它们找到空间的任何地方放置内存。

这个想法正确吗?如果是这样,汇编程序如何完成?

而且,绝对机器代码有哪些示例?

最佳答案

许多/大多数指令集具有pc相对地址,这意味着获取程序计数器的地址(与您正在执行的指令的地址相关),然后为其添加一个偏移量,并将其用于访问内存或分支等。那。那就是您所说的可重定位的东西。因为无论该指令在地址空间中的哪个位置,您都想跳转到的都是相对的。将整个代码和数据块移至其他地址,它们之间的距离仍然相对相同,因此相对寻址仍然有效。如果相等,则下一条指令将在这三条指令所在的位置(如果已跳过,则一条将被跳过,然后是一条跳过)将起作用。

绝对使用绝对地址,跳转到该确切地址,然后从该确切地址读取。如果相等,则跳转到0x1000。

汇编器不会这样做,编译器和/或程序员会这样做。通常,最终,编译后的代码最终将具有绝对寻址,尤其是如果您的代码由链接在一起的单独对象组成时。在编译时,编译器无法知道对象将在哪里结束,也无法知道外部引用在哪里或距离多远,因此通常不能假定它们将足够接近以进行pc相对寻址(通常具有范围限制) 。因此,编译器通常会为链接器生成一个占位符,以填充一个绝对地址。它确实取决于操作和指令集以及其他有关如何解决此外部地址问题的因素。最终,尽管基于项目大小,链接器最终仍会进行一些绝对寻址。因此,非默认值通常是用于生成位置无关代码的命令行选项-例如,PIC可能是编译器支持的内容。然后,编译器和链接器都必须做额外的工作以使这些项目位置独立。汇编语言程序员必须自己完成所有工作,汇编程序通常不会参与其中,它只是为您告诉它生成的指令创建机器代码。

novectors.s:

.globl _start
_start:
b reset
reset:
mov sp,#0xD8000000
bl notmain
ldr r0,=notmain
blx r0
hang: b hang

.globl dummy
dummy:
bx lr


你好ç

extern void dummy ( unsigned int );
int notmain ( void )
{
unsigned int ra;
for(ra=0;ra<1000;ra++) dummy(ra);
return(0);
}


memap(链接描述文件)
记忆
{
内存:原始= 0xD6000000,长度= 0x4000
}
部分
{
.text:{(.text)}> ram
}
生成文件

ARMGNU = arm-none-eabi
COPS = -Wall -O2 -nostdlib -nostartfiles -ffreestanding
all : hello_world.bin
clean :
rm -f *.o
rm -f *.bin
rm -f *.elf
rm -f *.list

novectors.o : novectors.s
$(ARMGNU)-as novectors.s -o novectors.o

hello.o : hello.c
$(ARMGNU)-gcc $(COPS) -c hello.c -o hello.o

hello_world.bin : memmap novectors.o hello.o
$(ARMGNU)-ld novectors.o hello.o -T memmap -o hello_world.elf
$(ARMGNU)-objdump -D hello_world.elf > hello_world.list
$(ARMGNU)-objcopy hello_world.elf -O binary hello_world.bin


hello_world.list(我们关心的部分)

Disassembly of section .text:

d6000000 <_start>:
d6000000: eaffffff b d6000004 <reset>

d6000004 <reset>:
d6000004: e3a0d336 mov sp, #-671088640 ; 0xd8000000
d6000008: eb000004 bl d6000020 <notmain>
d600000c: e59f0008 ldr r0, [pc, #8] ; d600001c <dummy+0x4>
d6000010: e12fff30 blx r0

d6000014 <hang>:
d6000014: eafffffe b d6000014 <hang>

d6000018 <dummy>:
d6000018: e12fff1e bx lr
d600001c: d6000020 strle r0, [r0], -r0, lsr #32

d6000020 <notmain>:
d6000020: e92d4010 push {r4, lr}
d6000024: e3a04000 mov r4, #0
d6000028: e1a00004 mov r0, r4
d600002c: e2844001 add r4, r4, #1
d6000030: ebfffff8 bl d6000018 <dummy>
d6000034: e3540ffa cmp r4, #1000 ; 0x3e8
d6000038: 1afffffa bne d6000028 <notmain+0x8>
d600003c: e3a00000 mov r0, #0
d6000040: e8bd4010 pop {r4, lr}
d6000044: e12fff1e bx lr


我在这里显示的是位置无关指令和位置相关指令的混合体。

例如,这两条指令是一个强制汇编器添加.word样式存储位置的快捷方式,然后链接程序必须为我们填充该位置。

ldr r0,=notmain
blx r0


0xD600001c是该位置。

    d600000c:   e59f0008    ldr r0, [pc, #8]    ; d600001c <dummy+0x4>
d6000010: e12fff30 blx r0
...
d600001c: d6000020 strle r0, [r0], -r0, lsr #32


并且用地址0xD6000020填充,这是一个绝对地址,因此要使该代码正常工作,功能notmain必须位于地址0xD6000020上,该地址不可重定位。但是示例的这一部分还演示了一些与位置无关的代码,

ldr r0, [pc, #8]


是我正在谈论的该指令集工作方式的pc相对地址是在执行时pc前面的两条指令,或者基本上在这种情况下,如果指令位于内存中的0xD600000c,那么执行时pc将是0xD6000014然后添加指令状态为8,则得到0xD600001C。但是,如果我们将完全相同的机器代码指令移至地址0x1000,然后将所有周围的二进制文件(包括其正在读取的内容)移至其中(0xD6000020)。基本上这样做:

    1000:   e59f0008    ldr r0, [pc, #8]    
1004: e12fff30 blx r0
...
1010: d6000020


这些指令仍然可以正常运行,而无需重新组装或重新链接。 0xD6000020代码sitll不必位于该固定地址位,而ldr pc和blx不要。

尽管反汇编器使用基于0xd6 ...的地址显示了这些内容,但bl和bne也是与pc相关的,您可以通过查看指令集文档来找到

d6000030:   ebfffff8    bl  d6000018 <dummy>
d6000034: e3540ffa cmp r4, #1000 ; 0x3e8
d6000038: 1afffffa bne d6000028 <notmain+0x8>


0xD6000030在执行时的pc为0xD6000038,0xD6000038-0xD6000018 = 0x20,即8条指令。负8分之二补码为0xFFF..FFFF8,您可以看到该机器码ebfffff8的大部分为ffff8,这是扩展的符号,并添加到程序计数器中,基本上表示向后8个指令。对于1fffffa中的ffffa同样如此,这意味着如果不相等,则向后跳转6条指令。请记住,该指令集(手臂)假定pc是前面的两个指令,因此后6表示前两个,然后是后6或实际上是后4。

如果删除

d600000c:   e59f0008    ldr r0, [pc, #8]    ; d600001c <dummy+0x4>
d6000010: e12fff30 blx r0


然后,整个程序最终都是独立于位置的,如果您愿意(我碰巧知道它会发生),这是偶然的,但这不是因为我告诉工具要这样做,而是因为我使所有内容都变得紧密并且没有使用任何绝对寻址。

最后,当您说“链接器为它们找到空间的任何地方”时,如果您在我的链接器脚本中注意到,我告诉链接器将所有内容都从0xD6000000开始,则我没有指定任何文件名或函数,因此,如果没有告知,则此链接器将放置项目按照它们在命令行上指定的顺序。 hello.c代码位于第二位,因此,在链接器放置了novectors.s代码之后,链接器所在的位置恰好位于此位置之后,hello.c代码从0xD6000020开始。

无需研究每条指令即可轻松查看位置无关和无效的简单方法是更改​​链接程序脚本,以将代码放置在其他地址。

MEMORY
{
ram : ORIGIN = 0x1000, LENGTH = 0x4000
}
SECTIONS
{
.text : { *(.text*) } > ram
}


并查看什么机器代码更改(如果有),什么没有更改。

00001000 <_start>:
1000: eaffffff b 1004 <reset>

00001004 <reset>:
1004: e3a0d336 mov sp, #-671088640 ; 0xd8000000
1008: eb000004 bl 1020 <notmain>
100c: e59f0008 ldr r0, [pc, #8] ; 101c <dummy+0x4>
1010: e12fff30 blx r0

00001014 <hang>:
1014: eafffffe b 1014 <hang>

00001018 <dummy>:
1018: e12fff1e bx lr
101c: 00001020 andeq r1, r0, r0, lsr #32

00001020 <notmain>:
1020: e92d4010 push {r4, lr}
1024: e3a04000 mov r4, #0
1028: e1a00004 mov r0, r4
102c: e2844001 add r4, r4, #1
1030: ebfffff8 bl 1018 <dummy>
1034: e3540ffa cmp r4, #1000 ; 0x3e8
1038: 1afffffa bne 1028 <notmain+0x8>
103c: e3a00000 mov r0, #0
1040: e8bd4010 pop {r4, lr}
1044: e12fff1e bx lr

关于assembly - 什么是可重定位和绝对机器代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22889719/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com