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

Assembly 什么是可重定位和绝对机器代码?,assembly,relocation,Assembly,Relocation,在研究汇编程序时,我遇到了这些术语。我的想法是,在可重定位机器代码中,代码不依赖于静态RAM位置。汇编程序为我的程序指定RAM需求。内存可以放在链接器为它们找到空间的任何地方 这个想法正确吗?如果是,汇编程序是如何完成的 还有,什么是绝对机器代码的例子?任何在代码中实际包含地址的东西都有绝对地址。代码中不包含地址的程序(所有操作都使用相对地址完成)可以从任何地址运行 汇编程序不这样做,程序员这样做。我在过去做过一些,对于小的东西通常很容易,一旦你超出了相对跳跃的范围,就会变得相当痛苦。IIRC唯

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

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


还有,什么是绝对机器代码的例子?

任何在代码中实际包含地址的东西都有绝对地址。代码中不包含地址的程序(所有操作都使用相对地址完成)可以从任何地址运行

汇编程序不这样做,程序员这样做。我在过去做过一些,对于小的东西通常很容易,一旦你超出了相对跳跃的范围,就会变得相当痛苦。IIRC唯一的两种方法是在例程之间滑动相对跳转,或者向当前地址添加一个已知偏移量,按下它,然后返回。在过去,有第三种方法可以计算它并将其写入代码中,但这已不再被接受。这已经足够长了,我不会发誓没有其他的方法

IIRC“调用”没有绝对地址的东西的唯一方法是推送你想要返回的地址,计算地址,推送并返回


请注意,在实践中,您通常使用混合方法。汇编程序和链接器存储进行调整所需的信息,当程序加载到内存中时,它被修改为在加载时的任何地址运行。因此,内存中的实际图像是绝对的,但磁盘上的文件工作起来就像是相对的,但没有通常带来的所有麻烦。(请注意,所有实际生成本机代码的高级语言都使用相同的方法。)

许多/大多数指令集具有pc相对寻址,这意味着采用与正在执行的指令地址相关的程序计数器地址,然后在上面加一个偏移量,用它来访问内存或分支之类的东西。这就是你所说的可重新定位。因为不管指令在地址空间中的什么位置,你想要跳转到的东西都是相对的。将整个代码块和数据移动到其他地址,它们之间的距离仍然相对相同,因此相对寻址仍然有效。如果相等,则跳过下一条指令,无论这三条指令位于何处(如果跳过、跳过的指令和跳过后的指令)

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

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

Novectos.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
你好,c

extern void dummy ( unsigned int );
int notmain ( void )
{
    unsigned int ra;
    for(ra=0;ra<1000;ra++) dummy(ra);
    return(0);
}
hello_world.list(我们关心的部件)

0xD600001c是该位置

    d600000c:   e59f0008    ldr r0, [pc, #8]    ; d600001c <dummy+0x4>
    d6000010:   e12fff30    blx r0
...
    d600001c:   d6000020    strle   r0, [r0], -r0, lsr #32
是pc相对寻址吗?我刚才说的这个指令集的工作方式是在执行时,pc在前面两条指令,或者基本上在这种情况下,如果指令在内存中是0xD60000C,那么pc在执行时将是0xD6000014,然后在指令状态下加上8,得到0xD600001C。但如果我们将完全相同的机器代码指令移动到地址0x1000,并将所有周围的二进制文件(包括它正在读取的内容)(0xD6000020)移动到地址0x1000。基本上是这样做的:

    1000:   e59f0008    ldr r0, [pc, #8]    
    1004:   e12fff30    blx r0
...
    1010:   d6000020    
这些指令,机器代码仍然有效,不需要重新组装或链接。0xD6000020代码必须位于ldr pc和blx不允许的固定地址位

虽然反汇编程序显示这些带有0xd6。。。基于地址的bl和bne也是与pc相关的,您可以通过查看指令集文档来了解它们

d6000030:   ebfffff8    bl  d6000018 <dummy>
d6000034:   e3540ffa    cmp r4, #1000   ; 0x3e8
d6000038:   1afffffa    bne d6000028 <notmain+0x8>
看看有什么机器代码改变了,有什么没有改变

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
000011000:
1000:eaffffff b 1004
00001004 :
1004:e3a0d336 mov sp,#-671088640;0xd8000000
1008:eb000004 bl 1020
100c:e59f0008 ldr r0,[pc,#8];101c
1010:E12FF30 blx r0
00001014 :
1014:eafffffe b 1014
00001018 :
1018:E12FF1E bx lr
101c:00001020安第克r1、r0、r0、lsr#32
00001020 :
1020:e92d4010推送{r4,lr}
1024:e3a04000 mov r4,#0
1028:e1a00004 mov r0,r4
102c:e2844001添加r4、r4和#1
1030:ebfffff8 bl 1018
1034:e3540ffa cmp r4,#1000;0x3e8
1038:1AFFFA bne 1028
103c:e3a00000 mov r0,#0
1040:e8bd4010 pop{r4,lr}
1044:E12FF1E bx lr
基本上,“绝对”模式意味着代码和RAM变量将精确地放置在
ldr r0, [pc, #8]
    1000:   e59f0008    ldr r0, [pc, #8]    
    1004:   e12fff30    blx r0
...
    1010:   d6000020    
d6000030:   ebfffff8    bl  d6000018 <dummy>
d6000034:   e3540ffa    cmp r4, #1000   ; 0x3e8
d6000038:   1afffffa    bne d6000028 <notmain+0x8>
d600000c:   e59f0008    ldr r0, [pc, #8]    ; d600001c <dummy+0x4>
d6000010:   e12fff30    blx r0
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