代码之家  ›  专栏  ›  技术社区  ›  shs_sf

Linux页表指针取消引用到底发生了什么?

  •  3
  • shs_sf  · 技术社区  · 9 年前

    我试图研究Linux内核中的页表遍历。我使用标准的方法遍历页面表以找到PFN(例如,不是实际代码):

        pgd_t *pgd; pte_t *ptep; pte_t pte; pud_t *pud; pmd_t *pmd;
        struct page *pagePtr = NULL;
        struct mm_struct *mm = current->mm;
        pgd = pgd_offset(mm, addr);
        pud = getPud(pgd, addr);
        pmd = pmd_offset(pud, addr);
        ptep = pte_offset_map(pmd, addr);
        size_t pfn = pte_pfn(pte);
    

    系统是

    CPU:Intel(R)Core(TM)i7-3770

    CPU@3.40GHz

    操作系统:Linux Fedora版本22(二十二)内核:4.4.4-200.fc22.x86_64

    我试图理解pgd指针是如何去引用pud指针的。我将简单代码放入getPud函数:

    noinline pud_t *getPud(pgd_t *pgdPtr, unsigned long addr).
    {
        return pud_offset(pgdPtr, addr);
    }
    

    并尝试通过objdump将其分解

    00000000000000b0 <getPud>:
      b0:   e8 00 00 00 00          callq  b5 <getPud+0x5>
      b5:   55                      push   %rbp
      b6:   48 8b 3f                mov    (%rdi),%rdi
      b9:   48 89 e5                mov    %rsp,%rbp
      bc:   ff 14 25 00 00 00 00    callq  *0x0
      c3:   48 c1 ee 1b             shr    $0x1b,%rsi
      c7:   48 ba 00 00 00 00 00    movabs $0xffff880000000000,%rdx
      ce:   88 ff ff
      d1:   81 e6 f8 0f 00 00       and    $0xff8,%esi
      d7:   48 01 d6                add    %rdx,%rsi
      da:   48 ba 00 f0 ff ff ff    movabs $0x3ffffffff000,%rdx
      e1:   3f 00 00
      e4:   48 21 d0                and    %rdx,%rax
      e7:   48 01 f0                add    %rsi,%rax
      ea:   5d                      pop    %rbp
      eb:   c3                      retq
      ec:   0f 1f 40 00             nopl   0x0(%rax)
    

    我的汇编知识不足以理解这样的结构 callq *0x0

    有人能告诉我getPud发生了什么吗?

    非常感谢。

    谢尔盖

    更新1

    我使用objdump反汇编我创建的LKM(cpes.ko)模块,以遍历页面表。

    >objdump -dr ./cpes.ko
    
    ./cpes.ko:     file format elf64-x86-64
    Disassembly of section .text:
    00000000000000b0 <getPud>:
      b0:   e8 00 00 00 00          callq  b5 <getPud+0x5>
                            b1: R_X86_64_PC32       __fentry__-0x4
      b5:   55                      push   %rbp
      b6:   48 8b 3f                mov    (%rdi),%rdi
      b9:   48 89 e5                mov    %rsp,%rbp
      bc:   ff 14 25 00 00 00 00    callq  *0x0
                            bf: R_X86_64_32S        pv_mmu_ops+0xf8
      c3:   48 c1 ee 1b             shr    $0x1b,%rsi
      c7:   48 ba 00 00 00 00 00    movabs $0xffff880000000000,%rdx
      ce:   88 ff ff
      d1:   81 e6 f8 0f 00 00       and    $0xff8,%esi
      d7:   48 01 d6                add    %rdx,%rsi
      da:   48 ba 00 f0 ff ff ff    movabs $0x3ffffffff000,%rdx
      e1:   3f 00 00
      e4:   48 21 d0                and    %rdx,%rax
      e7:   48 01 f0                add    %rsi,%rax
      ea:   5d                      pop    %rbp
      eb:   c3                      retq
      ec:   0f 1f 40 00             nopl   0x0(%rax)
    
    2 回复  |  直到 4 年前
        1
  •  4
  •   Peter Cordes    9 年前

    您正在查看 .o 正确的不是最终链接的二进制文件?这个 0x0 地址只是链接器将填充的占位符。(这是通过静态/全局函数指针的内存间接调用)。 pud_offset 正在内联到您的函数中。

    尝试 objdump -dr -dR 以显示反汇编输出中的重定位条目。

    或者更好,看看 gcc -S 输出具有符号名称。( -fverbose-asm 有时是有用的)。找出命令行 make 使用生成文件,并将其修改为使用 -S -o- 而不是 -c

        2
  •  1
  •   Roman Zaitsev    9 年前

    更好地查找源 code 如你所见,有一些 platform-specific address 魔术