c++でhello worldを書いてみた

22
C++ で Hello world でででででで 2015/5/17 hotpepsi

Upload: firewood

Post on 05-Aug-2015

2.931 views

Category:

Software


1 download

TRANSCRIPT

Page 1: C++でHello worldを書いてみた

C++ で Hello world を書いてみた

2015/5/17hotpepsi

Page 2: C++でHello worldを書いてみた

自己紹介 twitter: @hotpepsi 趣味 : 競技プログラミング、

テニス、ピアノ キャッチフレーズ :

bootstrap から Bootstrap まで

Page 3: C++でHello worldを書いてみた

デモ Ubuntu 14.04 x86-64

$ make -f hello_gen.mkg++ -fno-operator-names -o hello_gen_gen hello_gen_gen.cc./hello_gen_gen > numbers.ccg++ -o hello_gen hello_gen.cc./hello_gen > _.ccc -c -Wa,-R -w _.cld _.o -e _ -o hello./helloHello, world!

Page 4: C++でHello worldを書いてみた

ソースコードの先頭部分

_[]={'('-'!'|((','-' ')<<('$'-' '))|(('$'-' '|(('$'-' ')<<('$'-' ')))<<('('-' '))|(('$'-' '|(('#'-'!')<<('$'-' '))|((('/'-' ')<<('$'-' '))<<('('-' ')))<<('='-'-')),...

Page 5: C++でHello worldを書いてみた

記号プログラミング ( 二番煎じ )

Page 6: C++でHello worldを書いてみた

C で記号プログラミング ( 復習 )

記号のみでソースコードを記述 int 型の配列 _ を定義して、 text セグメント

に配置してプログラムとして実行する エントリポイントを _start ではなく _ にする

ことでアルファベット (main) を書くことを回避

というような記号だけのソースコードを生成するジェネレータを (C で ) 書いた

Page 7: C++でHello worldを書いてみた

強化点のご紹介

logo generator: http://www.schoolidolproject.com/

Page 8: C++でHello worldを書いてみた

強化点 1 2010: C 2015: C++ ← New!

Page 9: C++でHello worldを書いてみた

マクロがテンプレートに 2010: マクロ

MAKE32(_4,_8,_6,_5,_6,_C,_6,_C), // Hell 2015: テンプレート

Symbolizer<‘H’>().s // Hマクロは地獄

Page 10: C++でHello worldを書いてみた

struct Symbolizer Symbolizer<0>().s -> !””

文字列 ( ポインタ ) の否定はゼロ Symbolizer<1>().s -> !!””

ゼロの否定は 1 Symbolizer<n>().s -> Sym

bolizer<(n & 1)>().s | (Symbolizer<(n>>1)>().s << 1)

Page 11: C++でHello worldを書いてみた

テンプレートの優位性 マクロ :

0 から 16 までの値を用意する必要があった テンプレート :

特殊化により、最低限 0, 1, n を用意すれば、任意の数値が生成できる

例 : コンパイラにフィボナッチ数を計算させる 0 の部分を生成しないようにしたり、 2, 3, 4,

... と個別に用意すれば、コードがコンパクトに

Page 12: C++でHello worldを書いてみた

強化点 2 2010: バイナリ (0xB8, 0x04, ...) 2015: ニーモニック (mov ...)

Page 13: C++でHello worldを書いてみた

C++ でバイナリ生成といえば ... Xbyak

ニーモニックによる記述が可能に 可読性と保守性の大幅な向上

2010: MAKE32(_B,_8,_0,_4,_0,_0,_0,_0)

2015: mov(eax, 4);

Page 14: C++でHello worldを書いてみた

コード生成のステップ

1. コードジェネレータジェネレータ (C++) Xbyak でバイナリ生成 バイナリを Symbolizer の呼び出しに置換

して出力2. コードジェネレータ (C++)

Symbolizer により記号化して出力3. 記号だけのソースコード (C)

Page 15: C++でHello worldを書いてみた

強化点 3 2010: x86 2015: x86 + x86-64

Page 16: C++でHello worldを書いてみた

x86-64 対応 (1) 32bit/64bit の両方に対応したいが、 #i

fdef は減らしたい↓

同じバイト列を生成するようにする

Page 17: C++でHello worldを書いてみた

x86-64 対応 (2) x86 と x86-64 の命令バイト列はほぼ共

通 64bit の即値代入命令を使い、後半 32b

it に jmp 命令を埋め込むことで、 32bitモードの時だけ分岐する

これにより同じバイト列で両方に対応 デュアルアーキテクチャ

x86 と x64 の両方で動くシェルコードを書いてみるhttp://inaz2.hatenablog.com/entry/2014/07/06/185125

Page 18: C++でHello worldを書いてみた

objdump: x86

$ objdump -d hello

hello: file format elf32-i386

Disassembly of section .text:

08048080 <_>: 8048080: c7 44 24 f0 48 65 6c 6c c7 44 24 f4 6f 2c 20 77 .D$.Hell.D$.o, w 8048090: c7 44 24 f8 6f 72 6c 64 66 c7 44 24 fc 21 0a ba .D$.orldf.D$.!.. 80480a0: 0e 00 00 00 48 bb 01 00 00 00 eb 19 00 00 48 8d ....H.........H. 80480b0: 74 24 f0 bf 01 00 00 00 89 f8 0f 05 31 ff b8 3c t$..........1..< 80480c0: 00 00 00 0f 05 8d 4c 24 f0 b8 04 00 00 00 cd 80 ......L$........ 80480d0: 31 db b8 01 00 00 00 cd 80 00 00 00 1...........

Page 19: C++でHello worldを書いてみた

objdump: x86-64

$ objdump -d hello

hello: file format elf64-x86-64

Disassembly of section .text:

08048080 <_>: 8048080: c7 44 24 f0 48 65 6c 6c c7 44 24 f4 6f 2c 20 77 .D$.Hell.D$.o, w 8048090: c7 44 24 f8 6f 72 6c 64 66 c7 44 24 fc 21 0a ba .D$.orldf.D$.!.. 80480a0: 0e 00 00 00 48 bb 01 00 00 00 eb 19 00 00 48 8d ....H.........H. 80480b0: 74 24 f0 bf 01 00 00 00 89 f8 0f 05 31 ff b8 3c t$..........1..< 80480c0: 00 00 00 0f 05 8d 4c 24 f0 b8 04 00 00 00 cd 80 ......L$........ 80480d0: 31 db b8 01 00 00 00 cd 80 00 00 00 1...........

Page 20: C++でHello worldを書いてみた

完全に一致

ファイルフォーマット以外は完全に一致

Page 21: C++でHello worldを書いてみた

コードジェネレータジェネレータ

PutString(const std::string &message) {unsigned int *data = (unsigned int *)message.data();mov(dword[esp - 16], data[0]);mov(dword[esp - 12], data[1]);mov(dword[esp - 8], data[2]);mov(word[esp - 4], data[3]);mov(edx, message.length());dec(eax);mov(ebx, 1);jmp("@f");add(byte[eax], al);dec(eax);lea(esi, ptr[esp - 16]);mov(edi, 1);mov(eax, edi);syscall();xor(edi, edi);mov(eax, 60);syscall();

L("@@");lea(ecx, ptr[esp - 16]);mov(eax, 4);int80h();xor(ebx, ebx);mov(eax, 1);int80h();

}

スタック上にメッセージを置く

(x86/x86-64 共通 )

x86-64 用コード

x86 用コード

https://github.com/firewood/test/blob/master/hello_gen_gen.cc

Page 22: C++でHello worldを書いてみた

ソースコード_[]={'('-'!'|((','-' ')<<('$'-' '))|

(('$'-' '|(('$'-' ')<<('$'-' ')))<<('('-' '))|

(('$'-' '|(('#'-'!')<<('$'-' '))|

((('/'-' ')<<('$'-' '))<<('('-' ')))<<('='-'-')),... F0

24

C744

mov dword ptr[esp-16], imm