“ldr =”。静态与动态链接

问题描述 投票:0回答:1

这是这个问题的后续。

我明白在MacO上编程arm64时,我不能写:

    .text
    ldr  X0, =my_string

    .data
my_string:
    .asciz "Hello There"

但需要将

ldr
更改为:

    adrp, X0, my_string@PAGE
    add   X0, X0, my_string@PAGEOFF

对于普通的非 MacOs 加载程序,第一个将变成:

    ldr   X0, fakeLabel
    ...
fakeLabel: .quad my_string

然后

fakeLabel
处的值将在链接时固定。

同时,对于 MacO 和非 MacO,链接器需要

ldrp
所在的页面与
my_string
为 1 的页面之间的差异,并将该增量放入
ldrp
指令中。

根据我在另一页上给出的答案,前者是“动态”加载,因此非法,而后者是“静态”加载,合法。我不确定我是否理解其中的区别,因为两者都涉及更改指令。

ldrp
my_string
之间的增量是否以某种方式固定?文本和数据加载时是否总是相隔一定距离,即使我们不知道它们将加载到哪里?

我错过了什么吗?这有记录吗?

macos arm64
1个回答
0
投票

问题不在于指令 - 所有指令修改都发生在链接时(=静态)。这些都不是问题,在链接时你可以做任何你想做的事。

问题出在

fakeLabel
。那里存储了一个指针。由于 ASLR,指针需要在运行时(=动态)重新设置基准。如果当前在
.text
段中并且编写了
ldr xN, =...
,那么编译器插入的
fakeLabel
也将在
.text
段中。当进程启动时,动态链接器将尽职尽责地尝试重新设置指针的基址,但由于该段被映射为只读,因此这样做会使进程崩溃。

如果

fakeLabel
在数据段中发出,这不会成为问题,但由于 PC 相对
ldr
的最大偏移量为 ±1MiB,并且由于链接器可以根据需要自由重新排列段,因此这是不可能的在一般情况下。如果可能的话,它必须发出
adrp+ldr
并让链接器将其修复回 PC 相关的
ldr
,但编译器不允许将一条指令变成两条指令,并且如果您手动使用两条指令.. . 好吧,那么你不妨立即使用
adrp+add
并避免使用隐式指针。

© www.soinside.com 2019 - 2024. All rights reserved.