你为什么不试试呢?
hello:
.long .
.long 0x11111111
.long 0x22222222
.long 0x33333333
.long 0x44444444
.long 0x55555555
.long 0x66666666
.globl TEST
TEST:
adr r0,hello
bx lr
链接和反汇编
0000803c <hello>:
803c: 0000803c andeq r8, r0, r12, lsr r0
8040: 11111111 tstne r1, r1, lsl r1
8044: 22222222 eorcs r2, r2, #536870914 ; 0x20000002
8048: 33333333 teqcc r3, #-872415232 ; 0xcc000000
804c: 44444444 strbmi r4, [r4], #-1092 ; 0xfffffbbc
8050: 55555555 ldrbpl r5, [r5, #-1365] ; 0xfffffaab
8054: 66666666 strbtvs r6, [r6], -r6, ror #12
00008058 <TEST>:
8058: e24f0024 sub r0, pc, #36 ; 0x24
805c: e12fff1e bx lr
TEST 如我们预期的那样返回 0x803C。
列表中的第一项可能是您的谜。请注意他们如何使用点快捷方式来指示此处或此地址,因此列表中的第一项是列表开头的地址。其中 r0 已经他们可能已经完成了 mov r3,r0 但可能会燃烧该指令而不是仅加载它并用一条指令燃烧 ram。谁知道...
所以
.globl TEST
TEST:
adr r0,hello
ldmia r0,{r3}
mov r3,r0
bx lr
返回相同的 0x803C 值。
现在
.globl TEST
TEST:
adr r0,hello
ldmia r0,{r3}
subs r3,r0,r3
mov r0,r3
bx lr
正如预期的那样返回零,那么这一切的意义何在?请注意,这整个部分是与位置无关的,对吧?好吧,如果我将链接器更改为认为这是被加载到其他地方怎么办...
MEMORY
{
ram : ORIGIN = 0xA000, LENGTH = 0x1000000
}
生产
0000a03c <hello>:
a03c: 0000a03c andeq r10, r0, r12, lsr r0
a040: 11111111 tstne r1, r1, lsl r1
a044: 22222222 eorcs r2, r2, #536870914 ; 0x20000002
a048: 33333333 teqcc r3, #-872415232 ; 0xcc000000
a04c: 44444444 strbmi r4, [r4], #-1092 ; 0xfffffbbc
a050: 55555555 ldrbpl r5, [r5, #-1365] ; 0xfffffaab
a054: 66666666 strbtvs r6, [r6], -r6, ror #12
0000a058 <TEST>:
a058: e24f0024 sub r0, pc, #36 ; 0x24
a05c: e8900008 ldm r0, {r3}
a060: e0503003 subs r3, r0, r3
a064: e1a00003 mov r0, r3
a068: e12fff1e bx lr
但仍然在同一位置执行会给出 0xFFFFE000,即 -0x2000,因为我更改了链接器的方向,如果我将其更改为 0x5000 而不是 0xA000,我会得到 0x3000 作为差异。
所以这段代码的作用是
.long .
是编译时间,adr 是运行时并使用运行时 pc,因此此代码检测表所在的实际内存地址与表所在的编译时间地址之间的差异。如果表中的项目是编译时地址
hello:
.long .
.long one
.long two
.long three
one:
.long 0x44444444
two:
.long 0x55555555
three:
.long 0x66666666
0000503c <hello>:
503c: 0000503c andeq r5, r0, r12, lsr r0
5040: 0000504c andeq r5, r0, r12, asr #32
5044: 00005050 andeq r5, r0, r0, asr r0
5048: 00005054 andeq r5, r0, r4, asr r0
0000504c <one>:
504c: 44444444 strbmi r4, [r4], #-1092 ; 0xfffffbbc
00005050 <two>:
5050: 55555555 ldrbpl r5, [r5, #-1365] ; 0xfffffaab
00005054 <three>:
5054: 66666666 strbtvs r6, [r6], -r6, ror #12
然后为了使用这个跳转表或查找表,您需要知道编译地址与运行时地址,以便您可以调整代码中的编译时间地址。
使用物理和页面等术语,我认为页面是错误的,但它可能是虚拟与链接时间(我猜编译也是错误的术语,链接时间与运行时)它仍然是运行时与链接时间是否原因区别在于位置独立性或虚拟化。如果在操作系统上运行,则链接时间和运行时间应该是相同的,因为处理器(adr)至少不能像记录的那样检测到基于 PC 的值,并且 PC 不知道物理来自虚拟,所以不能以这种方式检测到物理,这是关闭的mmu 中的核心边缘。所以我认为物理和页面这两个术语在这里都被错误地使用了,但这只是我的看法。
如果您从编译器选项中删除 -fPIC 并且不使其位置独立代码,我想知道它是否不会打扰所有这些并按原样使用表。