libc無しにHello World

[やりたいこと]

・なるべく小さな実行ファイル(バイナリ)を作る

・そして、そのバイナリでアセンブラの勉強をする

 

[環境]

・CentOS7 x64 

 

[Cソースコード]

以下のWikiの「標準Cライブラリなし」ソースをそのまま使わせてもらいました。

フリースタンディング環境 - Wikipedia

 

・エントリポイントとなる関数は _start()という決まりがある

・その他の関数 _exit(), write()はインラインアセンブラで書かれている

 

現状、インラインアセンブラで何が書いているのか、理解していないです。

 

[コンパイル]

コンパイルは書かれている通りのコマンドでできました。

-Osを付けてアセンブラの最適化、-Wl,-sを付けてstripして、それぞれ容量が小さくなることも確認しました。

 

[逆アセンブル]

[root@cent7 ]# objdump -d -Mintel nostdlib

nostdlib:     ファイル形式 elf64-x86-64


セクション .text の逆アセンブル:

000000000040010c :
  40010c:	55                   	push   rbp
  40010d:	48 89 e5             	mov    rbp,rsp
  400110:	48 89 7d f8          	mov    QWORD PTR [rbp-0x8],rdi
  400114:	48 89 75 f0          	mov    QWORD PTR [rbp-0x10],rsi
  400118:	48 89 55 e8          	mov    QWORD PTR [rbp-0x18],rdx
  40011c:	48 8b 4d f8          	mov    rcx,QWORD PTR [rbp-0x8]
  400120:	4c 8b 45 f0          	mov    r8,QWORD PTR [rbp-0x10]
  400124:	4c 8b 4d e8          	mov    r9,QWORD PTR [rbp-0x18]
  400128:	48 c7 c0 01 00 00 00 	mov    rax,0x1
  40012f:	48 89 cf             	mov    rdi,rcx
  400132:	4c 89 c6             	mov    rsi,r8
  400135:	4c 89 ca             	mov    rdx,r9
  400138:	0f 05                	syscall 
  40013a:	5d                   	pop    rbp
  40013b:	c3                   	ret    

000000000040013c <_exit>:
  40013c:	55                   	push   rbp
  40013d:	48 89 e5             	mov    rbp,rsp
  400140:	48 89 7d f8          	mov    QWORD PTR [rbp-0x8],rdi
  400144:	48 8b 55 f8          	mov    rdx,QWORD PTR [rbp-0x8]
  400148:	48 c7 c0 3c 00 00 00 	mov    rax,0x3c
  40014f:	48 89 d7             	mov    rdi,rdx
  400152:	0f 05                	syscall 
  400154:	5d                   	pop    rbp
  400155:	c3                   	ret    

0000000000400156 <_start>:
  400156:	55                   	push   rbp
  400157:	48 89 e5             	mov    rbp,rsp
  40015a:	ba 0e 00 00 00       	mov    edx,0xe
  40015f:	be 7a 01 40 00       	mov    esi,0x40017a
  400164:	bf 01 00 00 00       	mov    edi,0x1
  400169:	e8 9e ff ff ff       	call   40010c 
  40016e:	bf 00 00 00 00       	mov    edi,0x0
  400173:	e8 c4 ff ff ff       	call   40013c <_exit>
  400178:	5d                   	pop    rbp
  400179:	c3                   	ret  

[ダンプ]

[root@cent7 ]# od -Ax -tx1z nostdlib
000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00  >.ELF............<
000010 02 00 3e 00 01 00 00 00 56 01 40 00 00 00 00 00  >..>.....V.@.....<
000020 40 00 00 00 00 00 00 00 f8 03 00 00 00 00 00 00  >@...............<
000030 00 00 00 00 40 00 38 00 03 00 40 00 09 00 06 00  >....@.8...@.....<
000040 01 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00  >................<
000050 00 00 40 00 00 00 00 00 00 00 40 00 00 00 00 00  >..@.......@.....<
000060 08 02 00 00 00 00 00 00 08 02 00 00 00 00 00 00  >................<
000070 00 00 20 00 00 00 00 00 04 00 00 00 04 00 00 00  >.. .............<
000080 e8 00 00 00 00 00 00 00 e8 00 40 00 00 00 00 00  >..........@.....<
000090 e8 00 40 00 00 00 00 00 24 00 00 00 00 00 00 00  >..@.....$.......<
0000a0 24 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00  >$...............<
0000b0 51 e5 74 64 06 00 00 00 00 00 00 00 00 00 00 00  >Q.td............<
0000c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  >................<
*
0000e0 10 00 00 00 00 00 00 00 04 00 00 00 14 00 00 00  >................<
0000f0 03 00 00 00 47 4e 55 00 7a 05 6c f3 61 6a 18 92  >....GNU.z.l.aj..<
000100 6c c7 09 08 8b f5 53 1f b5 fd 2b db 55 48 89 e5  >l.....S...+.UH..<
000110 48 89 7d f8 48 89 75 f0 48 89 55 e8 48 8b 4d f8  >H.}.H.u.H.U.H.M.<
000120 4c 8b 45 f0 4c 8b 4d e8 48 c7 c0 01 00 00 00 48  >L.E.L.M.H......H<
000130 89 cf 4c 89 c6 4c 89 ca 0f 05 5d c3 55 48 89 e5  >..L..L....].UH..<
000140 48 89 7d f8 48 8b 55 f8 48 c7 c0 3c 00 00 00 48  >H.}.H.U.H..<...H<
000150 89 d7 0f 05 5d c3 55 48 89 e5 ba 0e 00 00 00 be  >....].UH........<
000160 7a 01 40 00 bf 01 00 00 00 e8 9e ff ff ff bf 00  >z.@.............<
000170 00 00 00 e8 c4 ff ff ff 5d c3 48 65 6c 6c 6f 2c  >........].Hello,<
000180 20 77 6f 72 6c 64 21 0a 00 00 00 00 00 00 00 00  > world!.........<
000190 14 00 00 00 00 00 00 00 01 7a 52 00 01 78 10 01  >.........zR..x..<
0001a0 1b 0c 07 08 90 01 00 00 1c 00 00 00 1c 00 00 00  >................<
0001b0 5c ff ff ff 30 00 00 00 00 41 0e 10 86 02 43 0d  >\...0....A....C.<
0001c0 06 6b 0c 07 08 00 00 00 1c 00 00 00 3c 00 00 00  >.k..........<...<
0001d0 6c ff ff ff 1a 00 00 00 00 41 0e 10 86 02 43 0d  >l........A....C.<
0001e0 06 55 0c 07 08 00 00 00 1c 00 00 00 5c 00 00 00  >.U..........\...<
0001f0 66 ff ff ff 24 00 00 00 00 41 0e 10 86 02 43 0d  >f...$....A....C.<
000200 06 5f 0c 07 08 00 00 00 47 43 43 3a 20 28 47 4e  >._......GCC: (GN<
000210 55 29 20 34 2e 38 2e 35 20 32 30 31 35 30 36 32  >U) 4.8.5 2015062<
000220 33 20 28 52 65 64 20 48 61 74 20 34 2e 38 2e 35  >3 (Red Hat 4.8.5<
000230 2d 31 31 29 00 00 2e 73 79 6d 74 61 62 00 2e 73  >-11)...symtab..s<
000240 74 72 74 61 62 00 2e 73 68 73 74 72 74 61 62 00  >trtab..shstrtab.<
000250 2e 6e 6f 74 65 2e 67 6e 75 2e 62 75 69 6c 64 2d  >.note.gnu.build-<
000260 69 64 00 2e 74 65 78 74 00 2e 72 6f 64 61 74 61  >id..text..rodata<
000270 00 2e 65 68 5f 66 72 61 6d 65 00 2e 63 6f 6d 6d  >..eh_frame..comm<
000280 65 6e 74 00 00 00 00 00 00 00 00 00 00 00 00 00  >ent.............<
000290 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  >................<
0002a0 00 00 00 00 03 00 01 00 e8 00 40 00 00 00 00 00  >..........@.....<
0002b0 00 00 00 00 00 00 00 00 00 00 00 00 03 00 02 00  >................<
0002c0 0c 01 40 00 00 00 00 00 00 00 00 00 00 00 00 00  >..@.............<
0002d0 00 00 00 00 03 00 03 00 7a 01 40 00 00 00 00 00  >........z.@.....<
0002e0 00 00 00 00 00 00 00 00 00 00 00 00 03 00 04 00  >................<
0002f0 90 01 40 00 00 00 00 00 00 00 00 00 00 00 00 00  >..@.............<
000300 00 00 00 00 03 00 05 00 00 00 00 00 00 00 00 00  >................<
000310 00 00 00 00 00 00 00 00 01 00 00 00 04 00 f1 ff  >................<
000320 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  >................<
000330 0c 00 00 00 02 00 02 00 0c 01 40 00 00 00 00 00  >..........@.....<
000340 30 00 00 00 00 00 00 00 12 00 00 00 02 00 02 00  >0...............<
000350 3c 01 40 00 00 00 00 00 1a 00 00 00 00 00 00 00  ><.@.............<
000360 18 00 00 00 12 00 02 00 56 01 40 00 00 00 00 00  >........V.@.....<
000370 24 00 00 00 00 00 00 00 1f 00 00 00 10 00 04 00  >$...............<
000380 00 10 60 00 00 00 00 00 00 00 00 00 00 00 00 00  >..`.............<
000390 2b 00 00 00 10 00 04 00 00 10 60 00 00 00 00 00  >+.........`.....<
0003a0 00 00 00 00 00 00 00 00 32 00 00 00 10 00 04 00  >........2.......<
0003b0 00 10 60 00 00 00 00 00 00 00 00 00 00 00 00 00  >..`.............<
0003c0 00 6e 6f 73 74 64 6c 69 62 2e 63 00 77 72 69 74  >.nostdlib.c.writ<
0003d0 65 00 5f 65 78 69 74 00 5f 73 74 61 72 74 00 5f  >e._exit._start._<
0003e0 5f 62 73 73 5f 73 74 61 72 74 00 5f 65 64 61 74  >_bss_start._edat<
0003f0 61 00 5f 65 6e 64 00 00 00 00 00 00 00 00 00 00  >a._end..........<
000400 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  >................<
*
000430 00 00 00 00 00 00 00 00 1b 00 00 00 07 00 00 00  >................<
000440 02 00 00 00 00 00 00 00 e8 00 40 00 00 00 00 00  >..........@.....<
000450 e8 00 00 00 00 00 00 00 24 00 00 00 00 00 00 00  >........$.......<
000460 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00  >................<
000470 00 00 00 00 00 00 00 00 2e 00 00 00 01 00 00 00  >................<
000480 06 00 00 00 00 00 00 00 0c 01 40 00 00 00 00 00  >..........@.....<
000490 0c 01 00 00 00 00 00 00 6e 00 00 00 00 00 00 00  >........n.......<
0004a0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00  >................<
0004b0 00 00 00 00 00 00 00 00 34 00 00 00 01 00 00 00  >........4.......<
0004c0 02 00 00 00 00 00 00 00 7a 01 40 00 00 00 00 00  >........z.@.....<
0004d0 7a 01 00 00 00 00 00 00 0f 00 00 00 00 00 00 00  >z...............<
0004e0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00  >................<
0004f0 00 00 00 00 00 00 00 00 3c 00 00 00 01 00 00 00  >........<.......<
000500 02 00 00 00 00 00 00 00 90 01 40 00 00 00 00 00  >..........@.....<
000510 90 01 00 00 00 00 00 00 78 00 00 00 00 00 00 00  >........x.......<
000520 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00  >................<
000530 00 00 00 00 00 00 00 00 46 00 00 00 01 00 00 00  >........F.......<
000540 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  >0...............<
000550 08 02 00 00 00 00 00 00 2d 00 00 00 00 00 00 00  >........-.......<
000560 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00  >................<
000570 01 00 00 00 00 00 00 00 11 00 00 00 03 00 00 00  >................<
000580 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  >................<
000590 35 02 00 00 00 00 00 00 4f 00 00 00 00 00 00 00  >5.......O.......<
0005a0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00  >................<
0005b0 00 00 00 00 00 00 00 00 01 00 00 00 02 00 00 00  >................<
0005c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  >................<
0005d0 88 02 00 00 00 00 00 00 38 01 00 00 00 00 00 00  >........8.......<
0005e0 08 00 00 00 09 00 00 00 08 00 00 00 00 00 00 00  >................<
0005f0 18 00 00 00 00 00 00 00 09 00 00 00 03 00 00 00  >................<
000600 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  >................<
000610 c0 03 00 00 00 00 00 00 37 00 00 00 00 00 00 00  >........7.......<
000620 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00  >................<
000630 00 00 00 00 00 00 00 00                          >........<
000638

[コードセクション]

[root@cent7 ]# readelf -S nostdlib
9 個のセクションヘッダ、始点オフセット 0x3f8:

セクションヘッダ:
  [番] 名前              タイプ           アドレス          オフセット
       サイズ            EntSize          フラグ Link  情報  整列
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .note.gnu.build-i NOTE             00000000004000e8  000000e8
       0000000000000024  0000000000000000   A       0     0     4
  [ 2] .text             PROGBITS         000000000040010c  0000010c
       000000000000006e  0000000000000000  AX       0     0     1
  [ 3] .rodata           PROGBITS         000000000040017a  0000017a
       000000000000000f  0000000000000000   A       0     0     1
  [ 4] .eh_frame         PROGBITS         0000000000400190  00000190
       0000000000000078  0000000000000000   A       0     0     8
  [ 5] .comment          PROGBITS         0000000000000000  00000208
       000000000000002d  0000000000000001  MS       0     0     1
  [ 6] .shstrtab         STRTAB           0000000000000000  00000235
       000000000000004f  0000000000000000           0     0     1
  [ 7] .symtab           SYMTAB           0000000000000000  00000288
       0000000000000138  0000000000000018           8     9     8
  [ 8] .strtab           STRTAB           0000000000000000  000003c0
       0000000000000037  0000000000000000           0     0     1
フラグのキー:
  W (write), A (alloc), X (実行), M (merge), S (文字列), l (large)
  I (情報), L (リンク順), G (グループ), T (TLS), E (排他), x (不明)
  O (追加の OS 処理が必要) o (OS 固有), p (プロセッサ固有)

[ToDo]

インラインアセンブラを理解する 

 

volatileの影響をアセンブリで比較

volatileはコンパイラによる最適化を抑止する修飾子のことだった気がする。

volatileの有無により、アセンブリがどう違うのかを比較してみる。

(どうでもいいけど、アセンブラアセンブリの違いがわからない。。。)

 

試してみた結果、volatile有りだと演算用のレジスタ(?)にコピーしてから、加算や比較処理を行うようになっている模様。細かいことはアセンブラが読めないのでわかりません。

[shin@cent6-5 volatile]$ cat loop.c
int
main()
{
  int i;
  for(i=0; i<1000000000; i++){}
}
[shin@cent6-5 volatile]$ 
[shin@cent6-5 volatile]$ cat loop_vol.c
int
main()
{
  volatile int i;
  for(i=0; i<1000000000; i++){}
}
[shin@cent6-5 volatile]$ 
[shin@cent6-5 volatile]$ 
[shin@cent6-5 volatile]$ diff loop.s loop_vol.s
1c1
< 	.file	"loop.c"
---
> 	.file	"loop_vol.c"
16c16,18
< 	addl	$1, -4(%rbp)
---
> 	movl	-4(%rbp), %eax
> 	addl	$1, %eax
> 	movl	%eax, -4(%rbp)
18c20,21
< 	cmpl	$999999999, -4(%rbp)
---
> 	movl	-4(%rbp), %eax
> 	cmpl	$999999999, %eax
[shin@cent6-5 volatile]$ 
[shin@cent6-5 volatile]$ 
[shin@cent6-5 volatile]$ cat loop.s
	.file	"loop.c"
	.text
.globl main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movl	$0, -4(%rbp)      ★変数i(rbp)を0で初期化
	jmp	.L2             ★L2にジャンプ
.L3:
	addl	$1, -4(%rbp)      ★変数i(rbp)に1を加算
.L2:
	cmpl	$999999999, -4(%rbp)  ★ループの条件判定
	jle	.L3             ★判定結果に基づきL3にジャンプ
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-4)"
	.section	.note.GNU-stack,"",@progbits
[shin@cent6-5 volatile]$ 
[shin@cent6-5 volatile]$ 
[shin@cent6-5 volatile]$ cat loop_vol.s
	.file	"loop_vol.c"
	.text
.globl main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movl	$0, -4(%rbp)
	jmp	.L2
.L3:
	movl	-4(%rbp), %eax     ★別のレジスタにコピー
	addl	$1, %eax
	movl	%eax, -4(%rbp)     ★元のレジスタに書き戻し
.L2:
	movl	-4(%rbp), %eax     ★別のレジスタにコピー
	cmpl	$999999999, %eax
	jle	.L3
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-4)"
	.section	.note.GNU-stack,"",@progbits
[shin@cent6-5 volatile]$ 

参考にさせて頂いたサイト

X86アセンブラ/GASでの文法 - Wikibooks

アドレッシングモード - Wikipedia

プログラミングノート - x86

「組み込み」ならではの基礎知識 

gccはプリプロセス、コンパイル、アセンブル、リンク

gccコンパイルするツールという認識しかなかったけど、プリプロセス、コンパイルアセンブル、リンクという4つの処理をまとめて行ってくれていたらしい。

以下のコマンドで1つずつ処理を進められるので、中間ファイルを確認できる。

プリプロセス:gcc -E

 => #includeや#defineなどの文を展開する

コンパイルgcc -S

 => C言語のソースをアセンブリ言語のソースに変換する

アセンブルgcc -c

 => アセンブリ言語のソースを機械語のオブジェクトに変換する

リンク:gcc

 => オブジェクトをリンクして実行形式にする

 

-E, -S, -cはそれぞれ何の略かわからないけど、エスケープ(ESc)の順番だと思えば覚えられるかもしれない。。。

 

[shin@cent6-5 helloworld]$ gcc -E helloworld.c > helloworld.i
[shin@cent6-5 helloworld]$ gcc -S helloworld.i 
[shin@cent6-5 helloworld]$ ll
合計 28
-rw-rw-r--. 1 shin shin    61 11月  8 01:01 2014 helloworld.c
-rw-rw-r--. 1 shin shin 16736 11月 16 20:47 2014 helloworld.i
-rw-rw-r--. 1 shin shin   467 11月 16 20:57 2014 helloworld.s
[shin@cent6-5 helloworld]$ cat helloworld.s 
	.file	"helloworld.c"
	.section	.rodata
.LC0:
	.string	"hello world!"
	.text
.globl main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movl	$.LC0, %eax
	movq	%rax, %rdi
	movl	$0, %eax
	call	printf
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-4)"
	.section	.note.GNU-stack,"",@progbits
[shin@cent6-5 helloworld]$ gcc -c helloworld.s 
[shin@cent6-5 helloworld]$ ll
合計 32
-rw-rw-r--. 1 shin shin    61 11月  8 01:01 2014 helloworld.c
-rw-rw-r--. 1 shin shin 16736 11月 16 20:47 2014 helloworld.i
-rw-rw-r--. 1 shin shin  1512 11月 16 20:58 2014 helloworld.o
-rw-rw-r--. 1 shin shin   467 11月 16 20:57 2014 helloworld.s
[shin@cent6-5 helloworld]$ gcc -o helloworld helloworld.o
[shin@cent6-5 helloworld]$ ll
合計 40
-rwxrwxr-x. 1 shin shin  6432 11月 16 20:59 2014 helloworld
-rw-rw-r--. 1 shin shin    61 11月  8 01:01 2014 helloworld.c
-rw-rw-r--. 1 shin shin 16736 11月 16 20:47 2014 helloworld.i
-rw-rw-r--. 1 shin shin  1512 11月 16 20:58 2014 helloworld.o
-rw-rw-r--. 1 shin shin   467 11月 16 20:57 2014 helloworld.s
[shin@cent6-5 helloworld]$ ./helloworld 
hello world!

fileコマンド

今日もファイルを調べるコマンドについて。

fileコマンドでファイルの種類がわかる。

 ASCIIかUTF-8かバイナリかなど。。。

バイナリに対しては、ELF形式かとか動的リンクされてるとかstripされてるかとか、まだまだ調べ甲斐がありそう。

[shin@cent6-5 helloworld]$ file helloworld.c 
helloworld.c: ASCII C program text
[shin@cent6-5 helloworld]$ file helloworld_jp.c 
helloworld_jp.c: UTF-8 Unicode C program text
[shin@cent6-5 helloworld]$ file /dev/cdrom 
/dev/cdrom: symbolic link to `sr0'
[shin@cent6-5 helloworld]$ file /dev/sr0 
/dev/sr0: block special
[shin@cent6-5 helloworld]$ file /mnt/
/mnt/: directory
[shin@cent6-5 helloworld]$ file /proc/meminfo 
/proc/meminfo: empty
[shin@cent6-5 helloworld]$ file a.out
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped

odコマンド

Linux上ではテキストファイルがどのように扱われるのか気になったので調べてみる。

 

odコマンドとやらでファイルがバイナリ表示できるようだ。

-xで16進表示。

-cでアスキー表示。

[shin@cent6-5 helloworld]$ od helloworld.c -x
0000000 6923 636e 756c 6564 3c20 7473 6964 2e6f
0000020 3e68 0a0a 6f76 6469 6d20 6961 286e 7b29
0000040 200a 7020 6972 746e 2866 6822 6c65 6f6c
0000060 7720 726f 646c 2221 3b29 7d0a 000a
0000075
[shin@cent6-5 helloworld]$ od helloworld.c -c
0000000   #   i   n   c   l   u   d   e       <   s   t   d   i   o   .
0000020   h   >  \n  \n   v   o   i   d       m   a   i   n   (   )   {
0000040  \n           p   r   i   n   t   f   (   "   h   e   l   l   o
0000060       w   o   r   l   d   !   "   )   ;  \n   }  \n
0000075