I’m trying to investigate page table walk in Linux kernel. I used standard way to walk through page table to find PFN (just for example, not actual code):
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);
The system is
CPU: Intel(R) Core(TM) i7-3770
CPU @ 3.40GHz
OS: Linux Fedora release 22 (Twenty Two) Kernel: 4.4.4-200.fc22.x86_64
I’m trying to understand how pgd pointer dereferenced to pud pointer. I put simple code into getPud function:
noinline pud_t *getPud(pgd_t *pgdPtr, unsigned long addr).
{
return pud_offset(pgdPtr, addr);
}
And try to disassemble it by 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)
My assembler knowledge is not enough to understand constructions like callq *0x0
Could someone please shed some light on what is going on in getPud?
Thank you
Sergey
Update 1
I used objdump to disassemble LKM (cpes.ko) module I created to walk through page table.
>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)
You're looking at disassembly of the .o
, right? Not the final linked binary? The 0x0
address is just a placeholder that the linker will fill in. (This is a memory-indirect call through a static/global function pointer). pud_offset
is getting inlined into your function.
Try objdump -dr
or -dR
to show the relocation entries in with the disassembly output.
Or better, look at gcc -S
output to have symbolic names. (-fverbose-asm
is sometimes helpful). Figure out the command line that make
builds your file with, and modify it to use -S -o-
instead of -c