| Understanding The Linux Kernel Initcall Mechanism: Creating Dynamic Function-Pointer Call Tables | |||
|---|---|---|---|
| <<< Previous | Chapter 4. Simple Examples | Next >>> | Blog |
I'm going to start with the code that we saw before in the section on code layout and modify it a bit so that different parts will now be in their own ELF sections:
/*
* Copyright (C) 2006 Trevor Woerner
*/
#include <stdio.h>
int add (int, int) __attribute__ ((section ("my_code_section")));
int global_val __attribute__ ((section ("my_data_section")));
int gval_init __attribute__ ((section ("my_data_section"))) = 29;
int add (int i, int j)
{
return i+j;
}
int
main (void)
{
int local_val = 25;
global_val = 17;
printf ("local_val: %d global_val: %d gval_init: %d\n",
local_val, global_val, gval_init);
printf ("%d + %d = %d\n", local_val, global_val,
add (local_val, global_val));
return 0;
}
|
Now when we do an objdump -t on the result we get the following (I'll spare you the details of the entire output, line up the columns properly, and also sort it for you):
00000000 F *UND* 00000039 printf@@GLIBC_2.0
00000000 F *UND* 00000187 __libc_start_main@@GLIBC_2.0
00000000 w *UND* 00000000 _Jv_RegisterClasses
00000000 w *UND* 00000000 __gmon_start__
00000000 l d *ABS* 00000000 .shstrtab
00000000 l d *ABS* 00000000 .strtab
00000000 l d *ABS* 00000000 .symtab
00000000 l d .comment 00000000 .comment
00000000 l df *ABS* 00000000 crtstuff.c
00000000 l df *ABS* 00000000 crtstuff.c
00000000 l df *ABS* 00000000 new.c
08048114 l d .interp 00000000 .interp
08048128 l d .note.ABI-tag 00000000 .note.ABI-tag
08048148 l d .hash 00000000 .hash
08048174 l d .dynsym 00000000 .dynsym
080481d4 l d .dynstr 00000000 .dynstr
08048234 l d .gnu.version 00000000 .gnu.version
08048240 l d .gnu.version_r 00000000 .gnu.version_r
08048260 l d .rel.dyn 00000000 .rel.dyn
08048268 l d .rel.plt 00000000 .rel.plt
08048280 g F .init 00000000 _init
08048280 l d .init 00000000 .init
08048298 l d .plt 00000000 .plt
080482d8 g F .text 00000000 _start
080482d8 l d .text 00000000 .text
080482fc l F .text 00000000 call_gmon_start
08048320 l F .text 00000000 __do_global_dtors_aux
08048354 l F .text 00000000 frame_dummy
0804837c g F .text 0000007a main
080483f8 g F .text 0000004f __libc_csu_init
08048448 g F .text 00000005 __libc_csu_fini
08048450 l F .text 00000000 __do_global_ctors_aux
08048478 g *ABS* 00000000 __start_my_code_section
08048478 g F my_code_section 0000000b add
08048478 l d my_code_section 00000000 my_code_section
08048483 g *ABS* 00000000 __stop_my_code_section
08048484 g F .fini 00000000 _fini
08048484 l d .fini 00000000 .fini
080484a0 g O .rodata 00000004 _fp_hw
080484a0 l d .rodata 00000000 .rodata
080484a4 g O .rodata 00000004 _IO_stdin_used
080484e8 l O .eh_frame 00000000 __FRAME_END__
080484e8 l d .eh_frame 00000000 .eh_frame
080494ec g *ABS* 00000000 .hidden __fini_array_end
080494ec g *ABS* 00000000 .hidden __fini_array_start
080494ec g *ABS* 00000000 .hidden __init_array_end
080494ec g *ABS* 00000000 .hidden __init_array_start
080494ec g *ABS* 00000000 .hidden __preinit_array_end
080494ec g *ABS* 00000000 .hidden __preinit_array_start
080494ec l O .ctors 00000000 __CTOR_LIST__
080494ec l d .ctors 00000000 .ctors
080494f0 l O .ctors 00000000 __CTOR_END__
080494f4 l O .dtors 00000000 __DTOR_LIST__
080494f4 l d .dtors 00000000 .dtors
080494f8 l O .dtors 00000000 __DTOR_END__
080494fc l O .jcr 00000000 __JCR_END__
080494fc l O .jcr 00000000 __JCR_LIST__
080494fc l d .jcr 00000000 .jcr
08049500 g O .dynamic 00000000 _DYNAMIC
08049500 l d .dynamic 00000000 .dynamic
080495c8 l d .got 00000000 .got
080495cc g O .got.plt 00000000 .hidden _GLOBAL_OFFSET_TABLE_
080495cc l d .got.plt 00000000 .got.plt
080495e4 w .data 00000000 data_start
080495e4 g .data 00000000 __data_start
080495e4 l d .data 00000000 .data
080495e8 g O .data 00000000 .hidden __dso_handle
080495ec l O .data 00000000 p.4582
080495f0 g *ABS* 00000000 __start_my_data_section
080495f0 g O my_data_section 00000004 gval_init
080495f0 l d my_data_section 00000000 my_data_section
080495f4 g O my_data_section 00000004 global_val
080495f8 g *ABS* 00000000 __bss_start
080495f8 g *ABS* 00000000 __stop_my_data_section
080495f8 g *ABS* 00000000 _edata
080495f8 l O .bss 00000001 completed.4583
080495f8 l d .bss 00000000 .bss
080495fc g *ABS* 00000000 _end
|
Running the executable gives:
[trevor]$ ./sections
local_val: 25 global_val: 17 gval_init: 29
25 + 17 = 42
|
The first thing to note is that the executable works! (yea!) The second thing you should notice are the existance of new section names (my_code_section and my_data_section) in the executable image. You will also notice that in these sections are found the objects that we placed in them.
...
08048478 g *ABS* 00000000 __start_my_code_section
08048478 g F my_code_section 0000000b add
08048478 l d my_code_section 00000000 my_code_section
08048483 g *ABS* 00000000 __stop_my_code_section
...
080495f0 g *ABS* 00000000 __start_my_data_section
080495f0 g O my_data_section 00000004 gval_init
080495f0 l d my_data_section 00000000 my_data_section
080495f4 g O my_data_section 00000004 global_val
080495f8 g *ABS* 00000000 __bss_start
080495f8 g *ABS* 00000000 __stop_my_data_section
|
You may have just asked yourself: "In the generated my_data_section above, why did the gval_init object come first?". Having a look at the generated assembly (gcc -S) helps us to investigate this question:
.globl gval_init
.section my_data_section,"aw",@progbits
.align 4
.type gval_init, @object
.size gval_init, 4
gval_init:
.long 29
.section my_code_section,"ax",@progbits
.globl add
.type add, @function
add:
pushl %ebp
movl %esp, %ebp
movl 12(%ebp), %eax
addl 8(%ebp), %eax
leave
ret
.size add, .-add
.section .rodata
.align 4
.LC0:
.string "local_val: %d global_val: %d gval_init: %d\n"
.LC1:
.string "%d + %d = %d\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
subl %eax, %esp
movl $25, -4(%ebp)
movl $17, global_val
movl gval_init, %eax
movl global_val, %edx
pushl %eax
pushl %edx
pushl -4(%ebp)
pushl $.LC0
call printf
addl $16, %esp
movl global_val, %eax
pushl %eax
pushl -4(%ebp)
call add
addl $8, %esp
movl global_val, %edx
pushl %eax
pushl %edx
pushl -4(%ebp)
pushl $.LC1
call printf
addl $16, %esp
movl $0, %eax
leave
ret
.size main, .-main
.globl global_val
.section my_data_section
.align 4
.type global_val, @object
.size global_val, 4
global_val:
.zero 4
|
Basically, the answer to the above question "why gval_init ended up first" is that gcc separated them that way. If we make them both the same type of global variable we'll see that gcc will only create one segment for both of them, and that they'll appear in our segment in the order in which they're found in the source code:
code:
int global_val __attribute__ ((section ("my_data_section")));
int gval_init __attribute__ ((section ("my_data_section")));
assembly: (at the bottom of file)
.globl global_val
.section my_data_section,"aw",@progbits
.align 4
.type global_val, @object
.size global_val, 4
global_val:
.zero 4
.globl gval_init
.align 4
.type gval_init, @object
.size gval_init, 4
gval_init:
.zero 4
objdump -t | sort:
080495f0 g *ABS* 00000000 __start_my_data_section
080495f0 g O my_data_section 00000004 global_val
080495f0 l d my_data_section 00000000 my_data_section
080495f4 g O my_data_section 00000004 gval_init
080495f8 g *ABS* 00000000 __bss_start
080495f8 g *ABS* 00000000 __stop_my_data_section
|
code:
int gval_init __attribute__ ((section ("my_data_section")));
int global_val __attribute__ ((section ("my_data_section")));
assembly: (at the bottom of file)
.globl gval_init
.section my_data_section,"aw",@progbits
.align 4
.type gval_init, @object
.size gval_init, 4
gval_init:
.zero 4
.globl global_val
.align 4
.type global_val, @object
.size global_val, 4
global_val:
.zero 4
objdump -t | sort:
080495f0 g *ABS* 00000000 __start_my_data_section
080495f0 g O my_data_section 00000004 gval_init
080495f0 l d my_data_section 00000000 my_data_section
080495f4 g O my_data_section 00000004 global_val
080495f8 g *ABS* 00000000 __bss_start
080495f8 g *ABS* 00000000 __stop_my_data_section
|
| <<< Previous | Home | Next >>> |
| Section and Object Layout | Up | How the Linux Kernel initcall Mechanism Works |