assembly - 该汇编代码如何区分物理偏移量和页面偏移量?

标签 assembly memory-management arm virtual-memory

在研究linux源码的过程中,看到很多汇编代码都是这样的:

adr r0, 1f
ldmia   r0, {r3-r7}
mvn ip, #0
subs    r3, r0, r3  @ PHYS_OFFSET - PAGE_OFFSET
...
    .align
1:  .long   .
    .long   __pv_table_begin
    .long   __pv_table_end
2:  .long   __pv_phys_pfn_offset
    .long   __pv_offset

首先,它以adr开头,在上面的第一行中,我了解到adr r0, 1f表示它将保存1的地址: r0 开始。

ldmia r0, {r3-r7} 表示它将加载从保存在 r0 中的地址开始的值(指向 1:) 到寄存器 r3、r4、r5、r6、r7。因此,

r3=.

r4=__pv_table_begin

r5=__pv_table_end

r6=__pv_phys_pfn_offset

r7=__pv_offset

现在,我没有得到的部分: subs r3,r0,r3 我不完全确定 r3=. 是什么意思,但我猜想 r3 最终会包含它自己的地址值。

含糊地说,r0r3值都是指向相同位置1:的地址值。但我猜它们的值是不同的,因为一个是物理地址,另一个是虚拟地址。 (<- 这纯粹是我的猜测)。

这就是为什么我认为代码以某种方式试图通过 subs r3, r0, r3 来区分这两者。

我不确定我的猜测是否正确,即便如此,我也不知道哪个是物理地址和虚拟地址。此外,评论提到减法将产生物理偏移量和页面偏移量之间的差异。我已经阅读了与内存虚拟化相关的页面,但我无法将这些知识与此偏移量减法相关联。

最佳答案

你为什么不试试呢?

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。

虽然列表中的第一项可能是您的谜。请注意他们如何使用点快捷方式来指示此处或此地址,因此列表中的第一项是列表开头的地址。 which r0 already they could have just done a mov r3,r0 but may burning that instruction vs just loading it and burning ram with a instruction.谁知道...

所以

.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 并且不使其位置独立代码,我想知道它是否不会打扰所有这些而只是按原样使用该表。

关于assembly - 该汇编代码如何区分物理偏移量和页面偏移量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42338813/

相关文章:

linux - Fork 系统调用失败后 rax 中的返回值是多少?

c++ - 内联 asm 到 x64 - 理解

java - J2ME中 "System.gc()"的作用是什么?

algorithm - 最佳矩阵转置的缓存未命中率是多少?

azure - ARM 模板 - CustomLinuxScript 扩展失败 : Malformed status file (000003)Invalid status/status: failed

memory-management - ARM Cortex-A8:如何衡量缓存利用率?

c - STM32 NUCLEO F401RE无法写入GPIO BSRR中的某些位

组装32位左移器

assembly - 两个数组的总和,每个数组 n 个字节

c++ - 如何分析 Linux 可执行文件的静态内存使用情况?