Closed7

C プログラムと dynamic linker の entry point を追う

sankantsusankantsu

ELF の entry point は、ELF header の e_entry を見ればわかる。
普通、実行ファイルなら _start という symbol になっている。
https://www.sco.com/developers/gabi/2012-12-31/ch4.eheader.html

ふつう、_startcrt1.o とかみたいな名前の object file から来ている (ld がデフォルトでリンクしてくれる)。
crt は c runtime らしいよ

P.S.
shared object だと _start はあったりなかったり? あまりよくわかってないが...
_start が無い場合は .text の先頭だったり、0x0 だったり?
https://sourceware.org/binutils/docs/ld/Entry-Point.html

sankantsusankantsu

_start を entry point に設定しているのは誰? というと、たぶん ld になる。
ld --verbose を実行すると、デフォルトの linker script が出てくる。

ENTRY(_start)

こんな行があれば、entry point が _start という symbol になっているといって良さそう。
ld-e オプションとか、カスタムの linker script で上書きできるらしい。

sankantsusankantsu

でも、ほんとに _start から実行がはじまるの? というと、dynamic linker が関わる場合はそうでもない気がしてくる。
というのは、Program header に PT_INTERP がある場合、Program interpreter が実行したい実行ファイルより先に起動して、ライブラリロードやら (lazy bind ではない) 動的リンクやらを済ませてしまってから指定した実行ファイルの _start にジャンプしてくるはずだから。
つまり、dynamic linker の entry point こそ (PT_INTERP を含むプログラムの実行という意味では) 真に entry point と言えるような気もしてくる。

sankantsusankantsu

gdb で starti を実行すると、プログラム実行の最初の命令で止まる。
これは、ld-linux-x86-64.so.2_start になっていることが多いと思う。

手元で試したときは、こんな感じ

0x7ffff7fe4540 <_start>                 mov    %rsp,%rdi
0x7ffff7fe4543 <_start+3>               call   0x7ffff7fe51d0 <_dl_start>

2 つめの命令ですぐ _dl_start に飛ぶ。
なんだか、crt1.o にある普通の startup routine とは様子が違う感じ

sankantsusankantsu

ld.so の entry point はどこから来てるのか。
_dl_start は glibc の elf/rtld.c にいるみたいだったが、定義自体は得に変わったところもなく普通の関数に見える。

Makefile をよく読んでみても、カスタムの linker script を使っている様子もなくどこから entry point が来るのかよくわからない。
Compile option に -nostdlib, -nostartfiles やらついていて、どうやら普通の starup routine を使っていないらしいことはわかる。

さらに探すと、sysdeps/ 以下の dl-machine.h_start の定義があるのがわかった。
RTLD_START というマクロに asm で startup routine が埋め込まれており、これは結局 rtld.c の中で展開されている。
gdb で見たやつとも一致してるし、startup はこの部分で間違い無さそう

/* Initial entry point code for the dynamic linker.
   The C function `_dl_start' is the real entry point;
   its return value is the user program's entry point.  */
#define RTLD_START asm ("\n\
.text\n\
	.align 16\n\
.globl _start\n\
.globl _dl_start_user\n\
_start:\n\
	movq %rsp, %rdi\n\
	call _dl_start\n\
_dl_start_user:\n\
	# Save the user entry point address in %r12.\n\
    ()
sankantsusankantsu

とりあえず今日調べてわかったことを忘れないうちにまとめておいた。
TODO: 気が向いたらもうちょっとまとめて記事にするかも?

このスクラップは22日前にクローズされました