Assembly ARM组装中ADRP和ADRL指令的语义是什么?
PC相对偏移量处4KB页面的地址 将PC相对地址加载到寄存器中。它类似于ADR 指示ADRL可以加载比ADR更大范围的地址,因为 它生成两条数据处理指令 具体来说, ADRL汇编成两条指令,一条ADRP后跟ADD。如果 汇编程序不能在两条指令中构造地址,它 生成重新定位。然后链接器生成正确的偏移量。 ADRL产生与位置无关的代码,因为地址是 相对于PC计算Assembly ARM组装中ADRP和ADRL指令的语义是什么?,assembly,arm,arm64,instructions,position-independent-code,Assembly,Arm,Arm64,Instructions,Position Independent Code,PC相对偏移量处4KB页面的地址 将PC相对地址加载到寄存器中。它类似于ADR 指示ADRL可以加载比ADR更大范围的地址,因为 它生成两条数据处理指令 具体来说, ADRL汇编成两条指令,一条ADRP后跟ADD。如果 汇编程序不能在两条指令中构造地址,它 生成重新定位。然后链接器生成正确的偏移量。 ADRL产生与位置无关的代码,因为地址是 相对于PC计算 ADRP和ADRL指令做什么?更重要的是,和ADRP后接ADD如何构建PC相对地址?ADR ADR是一个简单的PC相对地址计算:您给它一个
ADRP
和ADRL
指令做什么?更重要的是,和ADRP
后接ADD
如何构建PC相对地址?ADR
ADR是一个简单的PC相对地址计算:您给它一个立即偏移量,它将相对当前PC的地址存储在寄存器中
例如,如果以下ADR指令位于内存中的位置0x4000:
adr x0, #1
adrp x0, #0x1000
然后,在执行此指令后,x0
现在包含值0x4001
我们可以试着做以下事情:
mov x0, #0x4001
但PC相对寻址有以下优点:
- 所有ARMv7/ARMv8指令的长度均为4字节。这在很大程度上与x86不同,x86的指令宽度是可变的
这简化了很多事情,但有一个不幸的含义:不能在一条指令中编码完整地址(4/8字节),因为我们需要一些位来编码指令本身
尽管我们无法存储完整地址,但我们可以通过PC的相对地址引用其中一些地址(适合编码的地址),这对于许多应用程序来说已经足够了,因为我们通常只跳转到附近的代码位置
这里的原理类似于存在
伪指令的原理:ldr=
- 它允许独立于位置的代码,这是避免共享库在内存中冲突的基础,但也有助于启用主文本段,另请参见:
- 生成的代码更小
添加?GNU GAS表明ADR只是一个伪op,总是组合成ADD或SUB:
此指令将标签地址加载到指定的寄存器中。该指令将根据标签的位置计算为PC相关的ADD或SUB指令。如果标签超出范围,或者未在与ADR指令相同的文件(和节)中定义,则将生成错误。此指令不会使用文字池
然而,在ARMv8 aarch64中,PC不能像通用寄存器一样在每一条指令中使用,因此ADR实际上很重要,并且有一个单独的编码:
ADRP
ADRP与ADR相似,但它:
- 相对于当前页面(而不仅仅是字节)移动页面(ADRP中的4KiB,P代表页面)
- 将12个低位归零
例如,如果以下ADRP指令位于内存中的位置0x4050:
adr x0, #1
adrp x0, #0x1000
然后,在执行此指令后,x0
现在包含值0x5000(+0x1000,并将前12位归零)
但是请注意,上面的语法只是教育性的,因为GNUGAS似乎不接受文字整型常量作为参数,而只接受符号。(或者,它将0x1000视为一个符号,而链接失败,这是沿着这些线进行的,现在没有时间完全理解它)
由于较低的12位被调零,为了计算完整地址,ADRP通常与ADD+:lo12:
重定位一起使用,如:
adrp x0, myvariable
add x0, x0, :lo12:myvariable
请注意,:lo12:
只是将myvariable
的较低12位提取为立即数,链接器生成的最终指令只是一条add x0,x0,#
,另请参见:and
与ADR相比,ADRP的优点是我们可以跳得更远(+-4GiB),代价是需要在ADRP之后进行额外的加法来设置较低的12位。ARMv8手册说明:
ADR指令向获取该指令的程序计数器的值添加一个有符号的21位立即数,然后将结果写入通用寄存器。这允许计算当前PC±1MB范围内的任何字节地址
ADRP指令将有符号的21位立即数向左移位12位,将其与程序计数器的值相加,并将底部12位清除为零,然后将结果写入通用寄存器。这允许在4KB对齐的内存区域计算地址。与ADD(立即数)指令或具有12位立即数偏移量的加载/存储指令结合使用,允许计算或访问当前PC±4GB范围内的任何地址
ADRP的另一个限制是,与ADR不同,如果将代码加载到内存中的位置相对于原始链接器偏移量(例如,由于ASLR)不偏移4K的倍数,则ADRP将中断。例如,如果您稍微向上移动一点,目标地址可能会落在下一页上,而PC位置会停留在旧页上,从而使ADRP指向错误的页。但是,仍然考虑依赖ADRP的可执行文件
Error: unknown mnemonic `adrl' -- `adrl r6,.Llabel'