I wrote this simple kernel module:
#include <linux/module.h> // for printk()
int init( void )
{
printk( "n Kello, everybody! nn" );
return 0;
}
void exit( void )
{
printk( "n Goodbye now... nn" );
}
MODULE_LICENSE("GPL");
module_init(init);
module_exit(exit);
and I'm trying to understand how the code gets translated to asm, so I objdumped it:
root@ubuntu:/home/alex/Desktop/KModule# objdump -D kmodule.ko
kmodule.ko: file format elf64-x86-64
Disassembly of section .note.gnu.build-id:
0000000000000000 <.note.gnu.build-id>:
0: 04 00 add $0x0,%al
2: 00 00 add %al,(%rax)
4: 14 00 adc $0x0,%al
6: 00 00 add %al,(%rax)
8: 03 00 add (%rax),%eax
a: 00 00 add %al,(%rax)
c: 47 rex.RXB
d: 4e 55 rex.WRX push %rbp
f: 00 5e ef add %bl,-0x11(%rsi)
12: 7d 73 jge 87 <__mod_vermagic5+0x4f>
14: 83 47 e9 4d addl $0x4d,-0x17(%rdi)
18: 98 cwtl
19: eb b8 jmp ffffffffffffffd3 <__mod_vermagic5+0xffffffffffffff9b>
1b: eb 18 jmp 35 <__module_depends+0x6>
1d: fb sti
1e: 84 28 test %ch,(%rax)
20: 73 db jae fffffffffffffffd <__mod_vermagic5+0xffffffffffffffc5>
22: 51 push %rcx
23: e4 .byte 0xe4
Disassembly of section .text:
0000000000000000 <init>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: e8 00 00 00 00 callq 9 <init+0x9>
9: 48 c7 c7 00 00 00 00 mov $0x0,%rdi
10: 31 c0 xor %eax,%eax
12: e8 00 00 00 00 callq 17 <init+0x17>
17: 31 c0 xor %eax,%eax
19: 5d pop %rbp
1a: c3 retq
1b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
0000000000000020 <cleanup_module>:
20: 55 push %rbp
21: 48 89 e5 mov %rsp,%rbp
24: e8 00 00 00 00 callq 29 <cleanup_module+0x9>
29: 48 c7 c7 00 00 00 00 mov $0x0,%rdi
30: 31 c0 xor %eax,%eax
32: e8 00 00 00 00 callq 37 <cleanup_module+0x17>
37: 5d pop %rbp
38: c3 retq
39: 00 00 add %al,(%rax)
...
Disassembly of section .rodata.str1.1:
0000000000000000 <.rodata.str1.1>:
0: 0a 20 or (%rax),%ah
2: 20 20 and %ah,(%rax)
4: 4b rex.WXB
5: 65 gs
6: 6c insb (%dx),%es:(%rdi)
7: 6c insb (%dx),%es:(%rdi)
8: 6f outsl %ds:(%rsi),(%dx)
9: 2c 20 sub $0x20,%al
b: 65 gs
c: 76 65 jbe 73 <__mod_vermagic5+0x3b>
e: 72 79 jb 89 <__mod_vermagic5+0x51>
10: 62 (bad)
11: 6f outsl %ds:(%rsi),(%dx)
12: 64 fs
13: 79 21 jns 36 <__module_depends+0x7>
15: 20 0a and %cl,(%rdx)
17: 0a 00 or (%rax),%al
19: 0a 20 or (%rax),%ah
1b: 20 20 and %ah,(%rax)
1d: 47 6f rex.RXB outsl %ds:(%rsi),(%dx)
1f: 6f outsl %ds:(%rsi),(%dx)
20: 64 fs
21: 62 (bad)
22: 79 65 jns 89 <__mod_vermagic5+0x51>
24: 20 6e 6f and %ch,0x6f(%rsi)
27: 77 2e ja 57 <__mod_vermagic5+0x1f>
29: 2e 2e 20 0a cs and %cl,%cs:(%rdx)
2d: 0a 00 or (%rax),%al
Disassembly of section .modinfo:
0000000000000000 <__mod_license27>:
0: 6c insb (%dx),%es:(%rdi)
1: 69 63 65 6e 73 65 3d imul $0x3d65736e,0x65(%rbx),%esp
8: 47 50 rex.RXB push %r8
a: 4c 00 73 72 rex.WR add %r14b,0x72(%rbx)
000000000000000c <__mod_srcversion31>:
c: 73 72 jae 80 <__mod_vermagic5+0x48>
e: 63 76 65 movslq 0x65(%rsi),%esi
11: 72 73 jb 86 <__mod_vermagic5+0x4e>
13: 69 6f 6e 3d 45 33 46 imul $0x4633453d,0x6e(%rdi),%ebp
1a: 38 45 32 cmp %al,0x32(%rbp)
1d: 30 39 xor %bh,(%rcx)
1f: 34 37 xor $0x37,%al
21: 44 32 31 xor (%rcx),%r14b
24: 33 30 xor (%rax),%esi
26: 32 35 44 36 39 34 xor 0x34393644(%rip),%dh # 34393670 <__mod_vermagic5+0x34393638>
2c: 34 45 xor $0x45,%al
...
000000000000002f <__module_depends>:
2f: 64 fs
30: 65 gs
31: 70 65 jo 98 <__mod_vermagic5+0x60>
33: 6e outsb %ds:(%rsi),(%dx)
34: 64 fs
35: 73 3d jae 74 <__mod_vermagic5+0x3c>
...
0000000000000038 <__mod_vermagic5>:
38: 76 65 jbe 9f <__mod_vermagic5+0x67>
3a: 72 6d jb a9 <__mod_vermagic5+0x71>
3c: 61 (bad)
3d: 67 69 63 3d 33 2e 30 imul $0x2e302e33,0x3d(%ebx),%esp
44: 2e
45: 30 2d 31 36 2d 67 xor %ch,0x672d3631(%rip) # 672d367c <__mod_vermagic5+0x672d3644>
4b: 65 6e outsb %gs:(%rsi),(%dx)
4d: 65 gs
4e: 72 69 jb b9 <__mod_vermagic5+0x81>
50: 63 20 movslq (%rax),%esp
52: 53 push %rbx
53: 4d 50 rex.WRB push %r8
55: 20 6d 6f and %ch,0x6f(%rbp)
58: 64 fs
59: 5f pop %rdi
5a: 75 6e jne ca <__mod_vermagic5+0x92>
5c: 6c insb (%dx),%es:(%rdi)
5d: 6f outsl %ds:(%rsi),(%dx)
5e: 61 (bad)
5f: 64 20 6d 6f and %ch,%fs:0x6f(%rbp)
63: 64 fs
64: 76 65 jbe cb <__mod_vermagic5+0x93>
66: 72 73 jb db <__mod_vermagic5+0xa3>
68: 69 .byte 0x69
69: 6f outsl %ds:(%rsi),(%dx)
6a: 6e outsb %ds:(%rsi),(%dx)
6b: 73 20 jae 8d <__mod_vermagic5+0x55>
...
Disassembly of section __mcount_loc:
0000000000000000 <__mcount_loc>:
...
Disassembly of section __versions:
0000000000000000 <____versions>:
0: 73 24 jae 26 <____versions+0x26>
2: 57 push %rdi
3: 41 00 00 add %al,(%r8)
6: 00 00 add %al,(%rax)
8: 6d insl (%dx),%es:(%rdi)
9: 6f outsl %ds:(%rsi),(%dx)
a: 64 fs
b: 75 6c jne 79 <____versions+0x79>
d: 65 gs
e: 5f pop %rdi
f: 6c insb (%dx),%es:(%rdi)
10: 61 (bad)
11: 79 6f jns 82 <____versions+0x82>
13: 75 74 jne 89 <____versions+0x89>
...
3d: 00 00 add %al,(%rax)
3f: 00 49 a0 add %cl,-0x60(%rcx)
42: e1 27 loope 6b <____versions+0x6b>
44: 00 00 add %al,(%rax)
46: 00 00 add %al,(%rax)
48: 70 72 jo bc <____versions+0xbc>
4a: 69 6e 74 6b 00 00 00 imul $0x6b,0x74(%rsi),%ebp
...
7d: 00 00 add %al,(%rax)
7f: 00 9a 0f 39 b4 00 add %bl,0xb4390f(%rdx)
85: 00 00 add %al,(%rax)
87: 00 6d 63 add %ch,0x63(%rbp)
8a: 6f outsl %ds:(%rsi),(%dx)
8b: 75 6e jne fb <__mod_vermagic5+0xc3>
8d: 74 00 je 8f <____versions+0x8f>
...
Disassembly of section .gnu.linkonce.this_module:
0000000000000000 <__this_module>:
...
18: 6b 6d 6f 64 imul $0x64,0x6f(%rbp),%ebp
1c: 75 6c jne 8a <__this_module+0x8a>
1e: 65 00 00 add %al,%gs:(%rax)
...
Disassembly of section .comment:
0000000000000000 <.comment>:
0: 00 47 43 add %al,0x43(%rdi)
3: 43 3a 20 rex.XB cmp (%r8),%spl
6: 28 55 62 sub %dl,0x62(%rbp)
9: 75 6e jne 79 <__mod_vermagic5+0x41>
b: 74 75 je 82 <__mod_vermagic5+0x4a>
d: 2f (bad)
e: 4c 69 6e 61 72 6f 20 imul $0x34206f72,0x61(%rsi),%r13
15: 34
16: 2e 36 2e 31 2d 39 75 cs ss xor %ebp,%cs:%ss:0x75627539(%rip) # 75627558 <__mod_vermagic5+0x75627520>
1d: 62 75
1f: 6e outsb %ds:(%rsi),(%dx)
20: 74 75 je 97 <__mod_vermagic5+0x5f>
22: 33 29 xor (%rcx),%ebp
24: 20 34 2e and %dh,(%rsi,%rbp,1)
27: 36 2e 31 00 ss xor %eax,%cs:%ss:(%rax)
2b: 00 47 43 add %al,0x43(%rdi)
2e: 43 3a 20 rex.XB cmp (%r8),%spl
31: 28 55 62 sub %dl,0x62(%rbp)
34: 75 6e jne a4 <__mod_vermagic5+0x6c>
36: 74 75 je ad <__mod_vermagic5+0x75>
38: 2f (bad)
39: 4c 69 6e 61 72 6f 20 imul $0x34206f72,0x61(%rsi),%r13
40: 34
41: 2e 36 2e 31 2d 39 75 cs ss xor %ebp,%cs:%ss:0x75627539(%rip) # 75627583 <__mod_vermagic5+0x7562754b>
48: 62 75
4a: 6e outsb %ds:(%rsi),(%dx)
4b: 74 75 je c2 <__mod_vermagic5+0x8a>
4d: 33 29 xor (%rcx),%ebp
4f: 20 34 2e and %dh,(%rsi,%rbp,1)
52: 36 2e 31 00 ss xor %eax,%cs:%ss:(%rax)
but something doesn't quite stack up with the rest...
how are the printk function called?? I can only see "callq 9", and that offset doesn't tell me anything.. it's the next instruction.. so what? The message "Kello" gets printed correctly but I can't find the code where this happens!
Besides.. how can this code access the string "Kello etc.." in section .rodata.str1.1 ? If this is a program segment mapped into ds register, shouldn't be something like "ds:0" to access it?
I'm quite confused..
Kernel modules are relocatable, and linked into the kernel when they are loaded. The actual memory addresses are only determined at that time. This is because the address for kernel functions, and the address at which the module will be loaded, are not known at compile-time.
If you look at the bytecode for all the call
instructions, you will see that they all have four zero bytes. When the module is loaded, these bytes will be replaced with the actual function address. The same is true for the string address: In the instruction mov $0x0,%rdi
, the zero will be replaced with the correct address.
The reason you see instructions like callq 9
and callq 17
is that the call
instruction specifies the address as relative to the next instruction. Since the relative address stored in the file is 0, the disassembler will show it as if the call
instruction is calling the instruction following it.
Using objdump -r
should show you the relocations for the module.