glibc 2.3之crti.o和crtn.o分析
1.crti.o和crtn.o的组成
crti.o和crtn.o也在csu目录下
crti.o来之crti.S,crtn.o来之crtn.S
而crti.S和crtn.S则都来之initfini.s
initfini.s则来之与sysdeps/generic/initfini.c
我们看看具体是如何生成这些文件的
gcc ../sysdeps/generic/initfini.c -c -O -Wall -Winline -Wstrict-prototypes -Wwrite-strings -g -g0 -fPIC -fno-inline-functions -march=i386 -mcpu=i386 -I../include -I. -I.. -I../libio -I../sysdeps/i386/elf -I../linuxthreads/sysdeps/unix/sysv/linux/i386 -I../linuxthreads/sysdeps/unix/sysv/linux -I../linuxthreads/sysdeps/pthread -I../sysdeps/pthread -I../linuxthreads/sysdeps/unix/sysv -I../linuxthreads/sysdeps/unix -I../linuxthreads/sysdeps/i386/i686 -I../linuxthreads/sysdeps/i386 -I../sysdeps/unix/sysv/linux/i386 -I../sysdeps/unix/sysv/linux -I../sysdeps/gnu -I../sysdeps/unix/common -I../sysdeps/unix/mman -I../sysdeps/unix/inet -I../sysdeps/unix/sysv/i386 -I../sysdeps/unix/sysv -I../sysdeps/unix/i386 -I../sysdeps/unix -I../sysdeps/posix -I../sysdeps/i386/i686/fpu -I../sysdeps/i386/i686 -I../sysdeps/i386/i486 -I../sysdeps/i386/fpu -I../sysdeps/i386 -I../sysdeps/wordsize-32 -I../sysdeps/ieee754/ldbl-96 -I../sysdeps/ieee754/dbl-64 -I../sysdeps/ieee754/flt-32 -I../sysdeps/ieee754 -I../sysdeps/generic/elf -I../sysdeps/generic -I /lib/modules/2.4.20-8smp/build/include -D_LIBC_REENTRANT -include ../include/libc-symbols.h -DHAVE_INITFINI -S -g0 -fPIC -fno-inline-functions -march=i386 -mcpu=i386 -finhibit-size-directive \
-fno-exceptions -o initfini.s //生成initfini.s
sed -n -e '1,/@HEADER_ENDS/p' \
-e '/@_.*_PROLOG_BEGINS/,/@_.*_PROLOG_ENDS/p' \
-e '/@TRAILER_BEGINS/,$p' initfini.s > crti.S//根据initfini.s生成crti.S
sed -n -e '/@TESTS_BEGIN/,/@TESTS_END/p' initfini.s | \
gawk -f defs.awk > defs.h
gcc crti.S -c -I../include -I. -I.. -I../libio -I../sysdeps/i386/elf -I../linuxthreads/sysdeps/unix/sysv/linux/i386 -I../linuxthreads/sysdeps/unix/sysv/linux -I../linuxthreads/sysdeps/pthread -I../sysdeps/pthread -I../linuxthreads/sysdeps/unix/sysv -I../linuxthreads/sysdeps/unix -I../linuxthreads/sysdeps/i386/i686 -I../linuxthreads/sysdeps/i386 -I../sysdeps/unix/sysv/linux/i386 -I../sysdeps/unix/sysv/linux -I../sysdeps/gnu -I../sysdeps/unix/common -I../sysdeps/unix/mman -I../sysdeps/unix/inet -I../sysdeps/unix/sysv/i386 -I../sysdeps/unix/sysv -I../sysdeps/unix/i386 -I../sysdeps/unix -I../sysdeps/posix -I../sysdeps/i386/i686/fpu -I../sysdeps/i386/i686 -I../sysdeps/i386/i486 -I../sysdeps/i386/fpu -I../sysdeps/i386 -I../sysdeps/wordsize-32 -I../sysdeps/ieee754/ldbl-96 -I../sysdeps/ieee754/dbl-64 -I../sysdeps/ieee754/flt-32 -I../sysdeps/ieee754 -I../sysdeps/generic/elf -I../sysdeps/generic -I /lib/modules/2.4.20-8smp/build/include -D_LIBC_REENTRANT -include ../include/libc-symbols.h -DHAVE_INITFINI -DASSEMBLER -I. -DGAS_SYNTAX -g0 -o crti.o
sed -n -e '1,/@HEADER_ENDS/p' \
-e '/@_.*_EPILOG_BEGINS/,/@_.*_EPILOG_ENDS/p' \
-e '/@TRAILER_BEGINS/,$p' initfini.s > crtn.S//根据initfini.s生成crtn.S
gcc crtn.S -c -I../include -I. -I.. -I../libio -I../sysdeps/i386/elf -I../linuxthreads/sysdeps/unix/sysv/linux/i386 -I../linuxthreads/sysdeps/unix/sysv/linux -I../linuxthreads/sysdeps/pthread -I../sysdeps/pthread -I../linuxthreads/sysdeps/unix/sysv -I../linuxthreads/sysdeps/unix -I../linuxthreads/sysdeps/i386/i686 -I../linuxthreads/sysdeps/i386 -I../sysdeps/unix/sysv/linux/i386 -I../sysdeps/unix/sysv/linux -I../sysdeps/gnu -I../sysdeps/unix/common -I../sysdeps/unix/mman -I../sysdeps/unix/inet -I../sysdeps/unix/sysv/i386 -I../sysdeps/unix/sysv -I../sysdeps/unix/i386 -I../sysdeps/unix -I../sysdeps/posix -I../sysdeps/i386/i686/fpu -I../sysdeps/i386/i686 -I../sysdeps/i386/i486 -I../sysdeps/i386/fpu -I../sysdeps/i386 -I../sysdeps/wordsize-32 -I../sysdeps/ieee754/ldbl-96 -I../sysdeps/ieee754/dbl-64 -I../sysdeps/ieee754/flt-32 -I../sysdeps/ieee754 -I../sysdeps/generic/elf -I../sysdeps/generic -I /lib/modules/2.4.20-8smp/build/include -D_LIBC_REENTRANT -include ../include/libc-symbols.h -DHAVE_INITFINI -DASSEMBLER -I. -DGAS_SYNTAX -g0 -o crtn.o
2.initfini.c(sysdeps/generic)
/* Special .init and .fini section support. 特别的.init和.fini节支持
*/
/* This file is compiled into assembly code which is then munged by a sed
script into two files: crti.s and crtn.s.
这个文件被编译成汇编代码,然后被一个sed脚本分割成两个文件crti.s和crtn.s
* crti.s puts a function prologue at the beginning of the
.init and .fini sections and defines global symbols for
those addresses, so they can be called as functions.
crti.s将一个函数的初始化部分放在.init和.fini节的开始处,定义这些地址
的全局符号,这样他们就能被当作函数来调用.
* crtn.s puts the corresponding function epilogues
in the .init and .fini sections.
crtn.s将相应的结束部分放在.init和.fini节中
*/
#include
/* We use embedded asm for .section unconditionally, as this makes it
easier to insert the necessary directives into crtn.S. */
#define SECTION(x) asm (".section " x )
/* Embed an #include to pull in the alignment and .end directives. */
asm ("\n#include \"defs.h\"");
/* The initial common code ends here. */
asm ("\n/*@HEADER_ENDS*/");
/* To determine whether we need .end and .align: */
asm ("\n/*@TESTS_BEGIN*/");
extern void dummy (void (*foo) (void));
void
dummy (void (*foo) (void))
{
if (foo)
(*foo) ();
}
asm ("\n/*@TESTS_END*/");
/* The beginning of _init: */
asm ("\n/*@_init_PROLOG_BEGINS*/");
static void
call_gmon_start(void)
{
extern void __gmon_start__ (void) __attribute__ ((weak)); /*weak_extern (__gmon_start__);*/
void (*gmon_start) (void) = __gmon_start__;
if (gmon_start)//gmon_start存在
gmon_start ();//调用
}
SECTION (".init");//.init节
extern void _init (void);
void
_init (void)
{
/* We cannot use the normal constructor mechanism in gcrt1.o because it
appears before crtbegin.o in the link, so the header elt of .ctors
would come after the elt for __gmon_start__. One approach is for
gcrt1.o to reference a symbol which would be defined by some library
module which has a constructor; but then user code's constructors
would come first, and not be profiled. */
call_gmon_start ();
asm ("ALIGN");
asm("END_INIT");
/* Now the epilog. */
asm ("\n/*@_init_PROLOG_ENDS*/");
asm ("\n/*@_init_EPILOG_BEGINS*/");
SECTION(".init");
}
asm ("END_INIT");
/* End of the _init epilog, beginning of the _fini prolog. */
asm ("\n/*@_init_EPILOG_ENDS*/");
asm ("\n/*@_fini_PROLOG_BEGINS*/");
SECTION (".fini");
extern void _fini (void);
void
_fini (void)
{
/* End of the _fini prolog. */
asm ("ALIGN");
asm ("END_FINI");
asm ("\n/*@_fini_PROLOG_ENDS*/");
{
/* Let GCC know that _fini is not a leaf function by having a dummy
function call here. We arrange for this call to be omitted from
either crt file. 让gcc生成pic代码?*/
extern void i_am_not_a_leaf (void);
i_am_not_a_leaf ();
}
/* Beginning of the _fini epilog. */
asm ("\n/*@_fini_EPILOG_BEGINS*/");
SECTION (".fini");
}
asm ("END_FINI");
/* End of the _fini epilog. Any further generated assembly (e.g. .ident)
is shared between both crt files. */
asm ("\n/*@_fini_EPILOG_ENDS*/");
asm ("\n/*@TRAILER_BEGINS*/");
/* End of file. */
这个文件需要对比生成的initfini.s看
3.initfini.s(csu)
.file "initfini.c"
#APP
#include "defs.h"
/*@HEADER_ENDS*/
/*@TESTS_BEGIN*/
#NO_APP
.text
.globl dummy
.type dummy,@function
dummy:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl 8(%ebp), %eax
testl %eax, %eax
je .L1
call *%eax
.L1:
leave
ret
#APP
/*@TESTS_END*/
/*@_init_PROLOG_BEGINS*/
#NO_APP
.type call_gmon_start,@function
call_gmon_start:
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $4, %esp
call .L5
.L5:
popl %ebx
addl $_GLOBAL_OFFSET_TABLE_+[.-.L5], %ebx
movl __gmon_start__@GOT(%ebx), %eax
testl %eax, %eax
je .L3
call *%eax
.L3:
movl -4(%ebp), %ebx
leave
ret
#APP
.section .init
#NO_APP
.globl _init
.type _init,@function
_init:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
call call_gmon_start
#APP
ALIGN
END_INIT
/*@_init_PROLOG_ENDS*/
/*@_init_EPILOG_BEGINS*/
.section .init
#NO_APP
leave
ret
#APP
END_INIT
/*@_init_EPILOG_ENDS*/
/*@_fini_PROLOG_BEGINS*/
.section .fini
#NO_APP
.globl _fini
.type _fini,@function
_fini:
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $4, %esp
call .L8
.L8:
popl %ebx
addl $_GLOBAL_OFFSET_TABLE_+[.-.L8], %ebx
#APP
ALIGN
END_FINI
/*@_fini_PROLOG_ENDS*/
#NO_APP
call i_am_not_a_leaf@PLT
#APP
/*@_fini_EPILOG_BEGINS*/
.section .fini
#NO_APP
movl -4(%ebp), %ebx
leave
ret
#APP
END_FINI
/*@_fini_EPILOG_ENDS*/
/*@TRAILER_BEGINS*/
.weak __gmon_start__
.ident "GCC: (GNU) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)"
4.crti.S
.file "initfini.c"
#APP
#include "defs.h"
/*@HEADER_ENDS*/
/*@_init_PROLOG_BEGINS*/
#NO_APP
.type call_gmon_start,@function
call_gmon_start:
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $4, %esp
call .L5
.L5:
popl %ebx
addl $_GLOBAL_OFFSET_TABLE_+[.-.L5], %ebx
movl __gmon_start__@GOT(%ebx), %eax
testl %eax, %eax
je .L3
call *%eax
.L3:
movl -4(%ebp), %ebx
leave
ret
#APP
.section .init
#NO_APP
.globl _init
.type _init,@function
_init:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
call call_gmon_start
#APP
ALIGN
END_INIT
/*@_init_PROLOG_ENDS*/
/*@_fini_PROLOG_BEGINS*/
.section .fini
#NO_APP
.globl _fini
.type _fini,@function
_fini:
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $4, %esp
call .L8
.L8:
popl %ebx
addl $_GLOBAL_OFFSET_TABLE_+[.-.L8], %ebx
#APP
ALIGN
END_FINI
/*@_fini_PROLOG_ENDS*/
/*@TRAILER_BEGINS*/
.weak __gmon_start__
.ident "GCC: (GNU) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)"
5.crtn.S
.file "initfini.c"
#APP
#include "defs.h"
/*@HEADER_ENDS*/
/*@_init_EPILOG_BEGINS*/
.section .init
#NO_APP
leave
ret
#APP
END_INIT
/*@_init_EPILOG_ENDS*/
/*@_fini_EPILOG_BEGINS*/
.section .fini
#NO_APP
movl -4(%ebp), %ebx
leave
ret
#APP
END_FINI
/*@_fini_EPILOG_ENDS*/
/*@TRAILER_BEGINS*/
.weak __gmon_start__
.ident "GCC: (GNU) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)"
6.defs.h
[root@mail /var/root/glibc-2.3/csu]# cat defs.h
#define END_INIT
#define END_FINI
#define ALIGN
#include
weak_extern (__gmon_start__)
7. defs.awk
[root@mail /var/root/glibc-2.3/csu]# cat defs.awk
/^[ ]*\.endp/ { need_endp = 1 }
/^[ ]*\.end/ { need_end = 1 }
/^[ ]*\.align/ { if($2 > max) max = $2; }
END {
if(need_endp)
{
print "#define END_INIT .endp _init";
print "#define END_FINI .endp _fini";
} else if(need_end)
{
print "#define END_INIT .end _init";
print "#define END_FINI .end _fini";
}
else
{
print "#define END_INIT";
print "#define END_FINI";
}
if(max)
print "#define ALIGN .align", max;
else
print "#define ALIGN";
print "#include ";
print "weak_extern (__gmon_start__)";
}
7.总结
可见crti和crtn就是将两个函数init和fini分别切成两截,他们的前半截放入crti,后半截放入crtn.
为什么要这么做呢?
如果有某些工作需要在main之间完成和main之后完成,那么,就可以将相应的代码放入目标文件的
.init和.fini节。在ld链接时,会按照给定的目标文件顺序,依次合并同名节。
这样就能将相应代码插入_init函数和_fini函数中,从而达到目的。
阅读(11680) | 评论(0) | 转发(1) |