SlideShare a Scribd company logo
しょしんしゃのためのhello world
wata2ki
はじめに
• 今日は、プログラミング初心者が最初に挑戦するhello worldについて発表します
• いつもネタが濃いとかマニアックと言われるので、しょしんしゃネタに挑戦してみました
• スクリプト言語はとても難しいので、使う言語はC言語です
• では、はじめてみましょう!
Hello world
#include <stdio.h>
int main(int argc, char *args[])
{
printf("Hello, world!n");
return 0;
}
まずは、ソースコードを書きます
gccでビルドします
gcc helloworld.c -o helloworld
実際に動かしてみましょう
strace ./helloworld
実行結果
execve("./helloworld", ["./helloworld"], 0x7ffdf3cb7e40 /* 26 vars */) = 0
brk(NULL) = 0x56098a5fc000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=91632, ...}) = 0
mmap(NULL, 91632, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f25389fb000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "177ELF21130000000030>0100026034200000"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2030544, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f25389f9000
mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f25383fa000
mprotect(0x7f25385e1000, 2097152, PROT_NONE) = 0
mmap(0x7f25387e1000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f25387e1000
mmap(0x7f25387e7000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f25387e7000
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7f25389fa4c0) = 0
mprotect(0x7f25387e1000, 16384, PROT_READ) = 0
mprotect(0x560988b70000, 4096, PROT_READ) = 0
mprotect(0x7f2538a12000, 4096, PROT_READ) = 0
munmap(0x7f25389fb000, 91632) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
brk(NULL) = 0x56098a5fc000
brk(0x56098a61d000) = 0x56098a61d000
write(1, "Hello, world!n", 14Hello, world!
) = 14
exit_group(0) = ?
では本題
• 実行結果について
• その実行ファイルを実行したときにコールされるシステムコールを、コンソールログに出力したもの
• straceというコマンドを使っています
• システムコールは、Linuxカーネルの機能を使うときにコールする処理です
それでは解説
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
brk(NULL) = 0x56098a5fc000
brk(0x56098a61d000) = 0x56098a61d000
write(1, "Hello, world!n", 14Hello, world!
) = 14
#include <stdio.h>
int main(int argc, char *args[])
{
printf("Hello, world!n");
return 0;
}
Hello worldに関係する部分は、実はこれだけ
• printfは、標準出力に対してフォー
マット文字列を出力するライブラリ
関数
• 標準出力はファイルディスクリプタ1
番と決まっている
• 1番のファイルが存在した後brkシス
テムコールでメモリを確保
• brkはmallocなどの動的メモリ確
保の裏でコールされる
• 最後に、文字列を1番に書き込み
それでは解説
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
brk(NULL) = 0x56098a5fc000
brk(0x56098a61d000) = 0x56098a61d000
write(1, "Hello, world!n", 14Hello, world!
) = 14
#include <stdio.h>
int main(int argc, char *args[])
{
fprintf(stderr,"Hello, world!n");
return 0;
}
バッファを持たない標準エラー出力を使ったらどうなるのか?
write(2, "Hello, world!n", 14Hello, world!
) = 14 標準エラー出力の場合
標準出力の場合
では、他の部分は何なの?!
execve("./helloworld", ["./helloworld"], 0x7ffdf3cb7e40 /* 26 vars */) = 0
brk(NULL) = 0x56098a5fc000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=91632, ...}) = 0
mmap(NULL, 91632, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f25389fb000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "177ELF21130000000030>0100026034200000"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2030544, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f25389f9000
mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f25383fa000
mprotect(0x7f25385e1000, 2097152, PROT_NONE) = 0
mmap(0x7f25387e1000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f25387e1000
mmap(0x7f25387e7000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f25387e7000
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7f25389fa4c0) = 0
mprotect(0x7f25387e1000, 16384, PROT_READ) = 0
mprotect(0x560988b70000, 4096, PROT_READ) = 0
mprotect(0x7f2538a12000, 4096, PROT_READ) = 0
munmap(0x7f25389fb000, 91632) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
brk(NULL) = 0x56098a5fc000
brk(0x56098a61d000) = 0x56098a61d000
write(1, "Hello, world!n", 14Hello, world!
) = 14
exit_group(0) = ?
実行ファイルを実行するときに最初に
コールするシステムコール
実行ファイルが終了するとき(プロセスが終了するとき)
にコールされるシステムコール
では、他の部分は何なの?!
execve("./helloworld", ["./helloworld"], 0x7ffdf3cb7e40 /* 26 vars */) = 0
brk(NULL) = 0x56098a5fc000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=91632, ...}) = 0
mmap(NULL, 91632, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f25389fb000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "177ELF21130000000030>0100026034200000"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2030544, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f25389f9000
mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f25383fa000
mprotect(0x7f25385e1000, 2097152, PROT_NONE) = 0
mmap(0x7f25387e1000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f25387e1000
mmap(0x7f25387e7000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f25387e7000
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7f25389fa4c0) = 0
mprotect(0x7f25387e1000, 16384, PROT_READ) = 0
mprotect(0x560988b70000, 4096, PROT_READ) = 0
mprotect(0x7f2538a12000, 4096, PROT_READ) = 0
munmap(0x7f25389fb000, 91632) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
brk(NULL) = 0x56098a5fc000
brk(0x56098a61d000) = 0x56098a61d000
write(1, "Hello, world!n", 14Hello, world!
) = 14
exit_group(0) = ?
ダイナミックリンカの処理
ダイナミックリンカとは?
• Linuxを初めとしたほとんどのOSでは、実行ファイルが共通で使うライブラリは、実行ファイル
の中(スタティックリンク)には置かずに、実行時にくっつける(ダイナミックリンク)する
• メリット
• ライブラリのバグ修正を行う場合に、スタティックリンクの場合はすべての実行ファイルを新しくしないといけ���い
が、ダイナミックリンクの場合はライブラリのファイルを更新するだけで済む
• 変数で使うメモリは各プロセスで個別に持つ必要があるが、全プロセス共通で良いプログラムコードと定数
(.text, .const)は1つで済むため、メモリ使用量が削減できる
• このメカニズムを実現するのがダイナミックリンカ(ld.so)
では、何をしているのか見てみよう
execve("./helloworld", ["./helloworld"], 0x7ffdf3cb7e40 /*
26 vars */) = 0
brk(NULL) = 0x56098a5fc000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such
file or directory)
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such
file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=91632, ...}) = 0
mmap(NULL, 91632, PROT_READ, MAP_PRIVATE, 3, 0) =
0x7f25389fb000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such
file or directory)
# cat /proc/30628/maps
555555554000-555555555000 r-xp 00000000 08:01 1213967 /home/watatuki/demo/helloworld3
555555754000-555555756000 rw-p 00000000 08:01 1213967 /home/watatuki/demo/helloworld3
7ffff7dd5000-7ffff7dfc000 r-xp 00000000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so
7ffff7ff7000-7ffff7ffa000 r--p 00000000 00:00 0 [vvar]
7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso]
7ffff7ffc000-7ffff7ffe000 rw-p 00027000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
この時点での、helloworldのメモリ
マップ
execveシステムコールで、実行ファ
イルとダイナミックリンカが、展開
されている
注. ログとメモリマップを同時にとれないので、アドレスがずれています
では、何をしているのか見てみよう
execve("./helloworld", ["./helloworld"], 0x7ffdf3cb7e40 /*
26 vars */) = 0
brk(NULL) = 0x56098a5fc000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such
file or directory)
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such
file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=91632, ...}) = 0
mmap(NULL, 91632, PROT_READ, MAP_PRIVATE, 3, 0) =
0x7f25389fb000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such
file or directory)
# cat /proc/30628/maps
555555554000-555555555000 r-xp 00000000 08:01 1213967 /home/watatuki/demo/helloworld3
555555754000-555555756000 rw-p 00000000 08:01 1213967 /home/watatuki/demo/helloworld3
7ffff7dd5000-7ffff7dfc000 r-xp 00000000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so
7ffff7ff7000-7ffff7ffa000 r--p 00000000 00:00 0 [vvar]
7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso]
7ffff7ffc000-7ffff7ffe000 rw-p 00027000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
これは動的メモリ(ヒープ)の初期位
置を取得している
ダイナミックリンクライブラリは、
ファイル名しか実行フィルに記録さ
れていないので、それがどこ(/lib?
/usr/lib?)にあるのかを記録した
キャッシュファイルを探している
注. ログとメモリマップを同時にとれないので、アドレスがずれています
では、何をしているのか見てみよう
execve("./helloworld", ["./helloworld"], 0x7ffdf3cb7e40 /*
26 vars */) = 0
brk(NULL) = 0x56098a5fc000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such
file or directory)
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such
file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=91632, ...}) = 0
mmap(NULL, 91632, PROT_READ, MAP_PRIVATE, 3, 0) =
0x7f25389fb000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such
file or directory)
555555554000-555555555000 r-xp 00000000 08:01 1213967 /home/watatuki/demo/helloworld3
555555754000-555555756000 rw-p 00000000 08:01 1213967 /home/watatuki/demo/helloworld3
7ffff7dd5000-7ffff7dfc000 r-xp 00000000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so
7ffff7fe0000-7ffff7ff7000 r--p 00000000 08:01 2362199 /etc/ld.so.cache (deleted)
7ffff7ff7000-7ffff7ffa000 r--p 00000000 00:00 0 [vvar]
7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso]
7ffff7ffc000-7ffff7ffe000 rw-p 00027000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
このmmap終了後、ld.so.cacheとい
うダイナミックリンカのキャッシュ
ファイルがマップされる
注. ログとメモリマップを同時にとれないので、アドレスがずれています
では、何をしているのか見てみよう(続き1)
access("/etc/ld.so.nohwcap", F_OK) = -1
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "177ELF21130000000030>0100026034200000"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2030544, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f25389f9000
mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f25383fa000
mprotect(0x7f25385e1000, 2097152, PROT_NONE) = 0
mmap(0x7f25387e1000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f25387e1000
mmap(0x7f25387e7000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f25387e7000
close(3) = 0
555555554000-555555555000 r-xp 00000000 08:01 1213967 /home/watatuki/demo/helloworld3
555555754000-555555756000 rw-p 00000000 08:01 1213967 /home/watatuki/demo/helloworld3
7ffff79e4000-7ffff7bcb000 r-xp 00000000 08:01 2102455 /lib/x86_64-linux-gnu/libc-2.27.so
7ffff7bcb000-7ffff7dcb000 ---p 001e7000 08:01 2102455 /lib/x86_64-linux-gnu/libc-2.27.so
7ffff7dcb000-7ffff7dd1000 rw-p 001e7000 08:01 2102455 /lib/x86_64-linux-gnu/libc-2.27.so
7ffff7dd1000-7ffff7dd5000 rw-p 00000000 00:00 0
7ffff7dd5000-7ffff7dfc000 r-xp 00000000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so
7ffff7fde000-7ffff7fe0000 rw-p 00000000 00:00 0
7ffff7fe0000-7ffff7ff7000 r--p 00000000 08:01 2362199 /etc/ld.so.cache (deleted)
7ffff7ff7000-7ffff7ffa000 r--p 00000000 00:00 0 [vvar]
7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso]
7ffff7ffc000-7ffff7ffe000 rw-p 00027000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
libc(システムコールや標準関数を提供するライブラリ)をメモリ上に展開
注. ログとメモリマップを同時にとれないので、のアドレスがずれています
では、何をしているのか見てみよう(続き2)
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7f25389fa4c0) = 0
mprotect(0x7f25387e1000, 16384, PROT_READ) = 0
mprotect(0x560988b70000, 4096, PROT_READ) = 0
mprotect(0x7f2538a12000, 4096, PROT_READ) = 0
munmap(0x7f25389fb000, 91632) = 0
555555554000-555555555000 r-xp 00000000 08:01 1213967 /home/watatuki/demo/helloworld3
555555754000-555555755000 r--p 00000000 08:01 1213967 /home/watatuki/demo/helloworld3
555555755000-555555756000 rw-p 00001000 08:01 1213967 /home/watatuki/demo/helloworld3
7ffff79e4000-7ffff7bcb000 r-xp 00000000 08:01 2102455 /lib/x86_64-linux-gnu/libc-2.27.so
7ffff7bcb000-7ffff7dcb000 ---p 001e7000 08:01 2102455 /lib/x86_64-linux-gnu/libc-2.27.so
7ffff7dcb000-7ffff7dcf000 r--p 001e7000 08:01 2102455 /lib/x86_64-linux-gnu/libc-2.27.so
7ffff7dcf000-7ffff7dd1000 rw-p 001eb000 08:01 2102455 /lib/x86_64-linux-gnu/libc-2.27.so
7ffff7dd1000-7ffff7dd5000 rw-p 00000000 00:00 0
7ffff7dd5000-7ffff7dfc000 r-xp 00000000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so
7ffff7fde000-7ffff7fe0000 rw-p 00000000 00:00 0
7ffff7fe0000-7ffff7ff7000 r--p 00000000 08:01 2362476 /etc/ld.so.cache (deleted)
7ffff7ff7000-7ffff7ffa000 r--p 00000000 00:00 0 [vvar]
7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso]
7ffff7ffc000-7ffff7ffd000 r--p 00027000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so
7ffff7ffd000-7ffff7ffe000 rw-p 00028000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
libc(システムコールや標準関数を提供するライブラリ)をメモリ上に展開
注. ログとメモリマップを同時にとれないので、のアドレスがずれています
たぶんダイナミックリンクテーブルを作り終わったの
で、テーブルの領域を書き込み禁止に変更してる
いらなくなった、ダイナミックリンカキャッシュを破
棄
まとめ
• 今日は、hallo worldがどんな動作をしているのか説明してみました
• 今回はシステムコールに着目してみました
• これが、スクリプト言語だともっとすごいことに。。。
• しょしんしゃ向けでも、こんなとらえかたがあると知ってもらえたらうれしいです!

More Related Content

しょしんしゃのためのhello world

  • 2. はじめに • 今日は、プログラミング初心者が最初に挑戦するhello worldについて発表します • いつもネタが濃いとかマニアックと言われるので、しょしんしゃネタに挑戦してみました • スクリプト言語はとても難しいので、使う言語はC言語です • では、はじめてみましょう!
  • 3. Hello world #include <stdio.h> int main(int argc, char *args[]) { printf("Hello, world!n"); return 0; } まずは、ソースコードを書きます gccでビルドします gcc helloworld.c -o helloworld 実際に動かしてみましょう strace ./helloworld
  • 4. 実行結果 execve("./helloworld", ["./helloworld"], 0x7ffdf3cb7e40 /* 26 vars */) = 0 brk(NULL) = 0x56098a5fc000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=91632, ...}) = 0 mmap(NULL, 91632, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f25389fb000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 read(3, "177ELF21130000000030>0100026034200000"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=2030544, ...}) = 0 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f25389f9000 mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f25383fa000 mprotect(0x7f25385e1000, 2097152, PROT_NONE) = 0 mmap(0x7f25387e1000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f25387e1000 mmap(0x7f25387e7000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f25387e7000 close(3) = 0 arch_prctl(ARCH_SET_FS, 0x7f25389fa4c0) = 0 mprotect(0x7f25387e1000, 16384, PROT_READ) = 0 mprotect(0x560988b70000, 4096, PROT_READ) = 0 mprotect(0x7f2538a12000, 4096, PROT_READ) = 0 munmap(0x7f25389fb000, 91632) = 0 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 brk(NULL) = 0x56098a5fc000 brk(0x56098a61d000) = 0x56098a61d000 write(1, "Hello, world!n", 14Hello, world! ) = 14 exit_group(0) = ?
  • 5. では本題 • 実行結果について • その実行ファイルを実行したときにコールされるシステムコールを、コンソールログに出力したもの • straceというコマンドを使っています • システムコールは、Linuxカーネルの機能を使うときにコールする処理です
  • 6. それでは解説 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 brk(NULL) = 0x56098a5fc000 brk(0x56098a61d000) = 0x56098a61d000 write(1, "Hello, world!n", 14Hello, world! ) = 14 #include <stdio.h> int main(int argc, char *args[]) { printf("Hello, world!n"); return 0; } Hello worldに関係する部分は、実はこれだけ • printfは、標準出力に対してフォー マット文字列を出力するライブラリ 関数 • 標準出力はファイルディスクリプタ1 番と決まっている • 1番のファイルが存在した後brkシス テムコールでメモリを確保 • brkはmallocなどの動的メモリ確 保の裏でコールされる • 最後に、文字列を1番に書き込み
  • 7. それでは解説 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 brk(NULL) = 0x56098a5fc000 brk(0x56098a61d000) = 0x56098a61d000 write(1, "Hello, world!n", 14Hello, world! ) = 14 #include <stdio.h> int main(int argc, char *args[]) { fprintf(stderr,"Hello, world!n"); return 0; } バッファを持たない標準エラー出力を使ったらどうなるのか? write(2, "Hello, world!n", 14Hello, world! ) = 14 標準エラー出力の場合 標準出力の場合
  • 8. では、他の部分は何なの?! execve("./helloworld", ["./helloworld"], 0x7ffdf3cb7e40 /* 26 vars */) = 0 brk(NULL) = 0x56098a5fc000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=91632, ...}) = 0 mmap(NULL, 91632, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f25389fb000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 read(3, "177ELF21130000000030>0100026034200000"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=2030544, ...}) = 0 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f25389f9000 mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f25383fa000 mprotect(0x7f25385e1000, 2097152, PROT_NONE) = 0 mmap(0x7f25387e1000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f25387e1000 mmap(0x7f25387e7000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f25387e7000 close(3) = 0 arch_prctl(ARCH_SET_FS, 0x7f25389fa4c0) = 0 mprotect(0x7f25387e1000, 16384, PROT_READ) = 0 mprotect(0x560988b70000, 4096, PROT_READ) = 0 mprotect(0x7f2538a12000, 4096, PROT_READ) = 0 munmap(0x7f25389fb000, 91632) = 0 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 brk(NULL) = 0x56098a5fc000 brk(0x56098a61d000) = 0x56098a61d000 write(1, "Hello, world!n", 14Hello, world! ) = 14 exit_group(0) = ? 実行ファイルを実行するときに最初に コールするシステムコール 実行ファイルが終了するとき(プロセスが終了するとき) にコールされるシステムコール
  • 9. では、他の部分は何なの?! execve("./helloworld", ["./helloworld"], 0x7ffdf3cb7e40 /* 26 vars */) = 0 brk(NULL) = 0x56098a5fc000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=91632, ...}) = 0 mmap(NULL, 91632, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f25389fb000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 read(3, "177ELF21130000000030>0100026034200000"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=2030544, ...}) = 0 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f25389f9000 mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f25383fa000 mprotect(0x7f25385e1000, 2097152, PROT_NONE) = 0 mmap(0x7f25387e1000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f25387e1000 mmap(0x7f25387e7000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f25387e7000 close(3) = 0 arch_prctl(ARCH_SET_FS, 0x7f25389fa4c0) = 0 mprotect(0x7f25387e1000, 16384, PROT_READ) = 0 mprotect(0x560988b70000, 4096, PROT_READ) = 0 mprotect(0x7f2538a12000, 4096, PROT_READ) = 0 munmap(0x7f25389fb000, 91632) = 0 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 brk(NULL) = 0x56098a5fc000 brk(0x56098a61d000) = 0x56098a61d000 write(1, "Hello, world!n", 14Hello, world! ) = 14 exit_group(0) = ? ダイナミックリンカの処理
  • 10. ダイナミックリンカとは? • Linuxを初めとしたほとんどのOSでは、実行ファイルが共通で使うライブラリは、実行ファイル の中(スタティックリンク)には置かずに、実行時にくっつける(ダイナミックリンク)する • メリット • ライブラリのバグ修正を行う場合に、スタティックリンクの場合はすべての実行ファイルを新しくしないといけない が、ダイナミックリンクの場合はライブラリのファイルを更新するだけで済む • 変数で使うメモリは各プロセスで個別に持つ必要があるが、全プロセス共通で良いプログラムコードと定数 (.text, .const)は1つで済むため、メモリ使用量が削減できる • このメカニズムを実現するのがダイナミックリンカ(ld.so)
  • 11. では、何をしているのか見てみよう execve("./helloworld", ["./helloworld"], 0x7ffdf3cb7e40 /* 26 vars */) = 0 brk(NULL) = 0x56098a5fc000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=91632, ...}) = 0 mmap(NULL, 91632, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f25389fb000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) # cat /proc/30628/maps 555555554000-555555555000 r-xp 00000000 08:01 1213967 /home/watatuki/demo/helloworld3 555555754000-555555756000 rw-p 00000000 08:01 1213967 /home/watatuki/demo/helloworld3 7ffff7dd5000-7ffff7dfc000 r-xp 00000000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so 7ffff7ff7000-7ffff7ffa000 r--p 00000000 00:00 0 [vvar] 7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso] 7ffff7ffc000-7ffff7ffe000 rw-p 00027000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so 7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] この時点での、helloworldのメモリ マップ execveシステムコールで、実行ファ イルとダイナミックリンカが、展開 されている 注. ログとメモリマップを同時にとれないので、アドレスがずれています
  • 12. では、何をしているのか見てみよう execve("./helloworld", ["./helloworld"], 0x7ffdf3cb7e40 /* 26 vars */) = 0 brk(NULL) = 0x56098a5fc000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=91632, ...}) = 0 mmap(NULL, 91632, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f25389fb000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) # cat /proc/30628/maps 555555554000-555555555000 r-xp 00000000 08:01 1213967 /home/watatuki/demo/helloworld3 555555754000-555555756000 rw-p 00000000 08:01 1213967 /home/watatuki/demo/helloworld3 7ffff7dd5000-7ffff7dfc000 r-xp 00000000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so 7ffff7ff7000-7ffff7ffa000 r--p 00000000 00:00 0 [vvar] 7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso] 7ffff7ffc000-7ffff7ffe000 rw-p 00027000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so 7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] これは動的メモリ(ヒープ)の初期位 置を取得している ダイナミックリンクライブラリは、 ファイル名しか実行フィルに記録さ れていないので、それがどこ(/lib? /usr/lib?)にあるのかを記録した キャッシュファイルを探している 注. ログとメモリマップを同時にとれないので、アドレスがずれています
  • 13. では、何をしているのか見てみよう execve("./helloworld", ["./helloworld"], 0x7ffdf3cb7e40 /* 26 vars */) = 0 brk(NULL) = 0x56098a5fc000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=91632, ...}) = 0 mmap(NULL, 91632, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f25389fb000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) 555555554000-555555555000 r-xp 00000000 08:01 1213967 /home/watatuki/demo/helloworld3 555555754000-555555756000 rw-p 00000000 08:01 1213967 /home/watatuki/demo/helloworld3 7ffff7dd5000-7ffff7dfc000 r-xp 00000000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so 7ffff7fe0000-7ffff7ff7000 r--p 00000000 08:01 2362199 /etc/ld.so.cache (deleted) 7ffff7ff7000-7ffff7ffa000 r--p 00000000 00:00 0 [vvar] 7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso] 7ffff7ffc000-7ffff7ffe000 rw-p 00027000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so 7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] このmmap終了後、ld.so.cacheとい うダイナミックリンカのキャッシュ ファイルがマップされる 注. ログとメモリマップを同時にとれないので、アドレスがずれています
  • 14. では、何をしているのか見てみよう(続き1) access("/etc/ld.so.nohwcap", F_OK) = -1 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 read(3, "177ELF21130000000030>0100026034200000"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=2030544, ...}) = 0 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f25389f9000 mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f25383fa000 mprotect(0x7f25385e1000, 2097152, PROT_NONE) = 0 mmap(0x7f25387e1000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f25387e1000 mmap(0x7f25387e7000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f25387e7000 close(3) = 0 555555554000-555555555000 r-xp 00000000 08:01 1213967 /home/watatuki/demo/helloworld3 555555754000-555555756000 rw-p 00000000 08:01 1213967 /home/watatuki/demo/helloworld3 7ffff79e4000-7ffff7bcb000 r-xp 00000000 08:01 2102455 /lib/x86_64-linux-gnu/libc-2.27.so 7ffff7bcb000-7ffff7dcb000 ---p 001e7000 08:01 2102455 /lib/x86_64-linux-gnu/libc-2.27.so 7ffff7dcb000-7ffff7dd1000 rw-p 001e7000 08:01 2102455 /lib/x86_64-linux-gnu/libc-2.27.so 7ffff7dd1000-7ffff7dd5000 rw-p 00000000 00:00 0 7ffff7dd5000-7ffff7dfc000 r-xp 00000000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so 7ffff7fde000-7ffff7fe0000 rw-p 00000000 00:00 0 7ffff7fe0000-7ffff7ff7000 r--p 00000000 08:01 2362199 /etc/ld.so.cache (deleted) 7ffff7ff7000-7ffff7ffa000 r--p 00000000 00:00 0 [vvar] 7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso] 7ffff7ffc000-7ffff7ffe000 rw-p 00027000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so 7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] libc(システムコールや標準関数を提供するライブラリ)をメモリ上に展開 注. ログとメモリマップを同時にとれないので、のアドレスがずれています
  • 15. では、何をしているのか見てみよう(続き2) close(3) = 0 arch_prctl(ARCH_SET_FS, 0x7f25389fa4c0) = 0 mprotect(0x7f25387e1000, 16384, PROT_READ) = 0 mprotect(0x560988b70000, 4096, PROT_READ) = 0 mprotect(0x7f2538a12000, 4096, PROT_READ) = 0 munmap(0x7f25389fb000, 91632) = 0 555555554000-555555555000 r-xp 00000000 08:01 1213967 /home/watatuki/demo/helloworld3 555555754000-555555755000 r--p 00000000 08:01 1213967 /home/watatuki/demo/helloworld3 555555755000-555555756000 rw-p 00001000 08:01 1213967 /home/watatuki/demo/helloworld3 7ffff79e4000-7ffff7bcb000 r-xp 00000000 08:01 2102455 /lib/x86_64-linux-gnu/libc-2.27.so 7ffff7bcb000-7ffff7dcb000 ---p 001e7000 08:01 2102455 /lib/x86_64-linux-gnu/libc-2.27.so 7ffff7dcb000-7ffff7dcf000 r--p 001e7000 08:01 2102455 /lib/x86_64-linux-gnu/libc-2.27.so 7ffff7dcf000-7ffff7dd1000 rw-p 001eb000 08:01 2102455 /lib/x86_64-linux-gnu/libc-2.27.so 7ffff7dd1000-7ffff7dd5000 rw-p 00000000 00:00 0 7ffff7dd5000-7ffff7dfc000 r-xp 00000000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so 7ffff7fde000-7ffff7fe0000 rw-p 00000000 00:00 0 7ffff7fe0000-7ffff7ff7000 r--p 00000000 08:01 2362476 /etc/ld.so.cache (deleted) 7ffff7ff7000-7ffff7ffa000 r--p 00000000 00:00 0 [vvar] 7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso] 7ffff7ffc000-7ffff7ffd000 r--p 00027000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so 7ffff7ffd000-7ffff7ffe000 rw-p 00028000 08:01 2102427 /lib/x86_64-linux-gnu/ld-2.27.so 7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] libc(システムコールや標準関数を提供するライブラリ)をメモリ上に展開 注. ログとメモリマップを同時にとれないので、のアドレスがずれています たぶんダイナミックリンクテーブルを作り終わったの で、テーブルの領域を書き込み禁止に変更してる いらなくなった、ダイナミックリンカキャッシュを破 棄
  • 16. まとめ • 今日は、hallo worldがどんな動作をしているのか説明してみました • 今回はシステムコールに着目してみました • これが、スクリプト言語だともっとすごいことに。。。 • しょしんしゃ向けでも、こんなとらえかたがあると知ってもらえたらうれしいです!