编译与虚拟机技术入门
“技多不压身”。内卷时代对编译和虚拟机技术有所了解是极好的。可是JVM太庞大了。
这个 虽然只有10KB,但它包含玩具级C编译器和x86虚拟机,阅读它可以快速入门,当然门楣很高:-)。
它是 基本能看懂的C编译器 的改进版,混合使用了自顶向下和自底向上(bison)分析。
① 你可以为它增加do语句等功能。
② 你可以为虚拟机增加指令。可写个t.c,main里return 0;再gcc -m32 -S t.c得到t.s,在里面写汇编指令,再
gcc -m32 -g t.s; gdb a.out; b main; run; disas /r; help disas. With a /r modifier, raw instructions in hex are included.
③ 你可以用Verilog实现虚拟机。Icarus Verilog is a Verilog simulation and synthesis tool. It operates as a compiler, compiling source code into some target format. The compiler can generate an intermediate form called vvp assembly. This intermediate form is executed by the `vvp' command.
④ .com可执行文件不分段,code从0x100开始。生成16位代码的.com,在DOSBox里运行。可以做点图形程序,画圆画线去毛刺等。
⑤ .iso文件的引导记录是啥格式?可以生成个bootable iso,用VirtualBox加载下。INT 13H能用吗?可以做个fdisk, BASIC解释器等。
⑥ Tiny C Compiler生成ELF可执行文件。读懂它起码可以明白ELF格式。
$ sudo apt-get install bison # bison一般默认已有
$ make
g++ -g -c -o toyc.o toyc.cpp
bison -d -o expr.cpp expr.y
g++ -g -c -o expr.o expr.cpp
g++ -o toyc toyc.o expr.o
g++ -g -c -o toyvm.o toyvm.cpp
g++ toyvm.o -o toyvm
$ toyc 1.c
生成code.bin和data.bin
$ toyvm # 装入code.bin和data.bin并执行之
$ objdump -b binary -m i386 -D code.bin # 查看汇编
---------------- 源码片段 -------------
void do_block(uint* plevel) {
uint pos, p2, p3, tt;
if (tk == T_IF) {
next_must_be_and_next('('); pos = do_test_expr(); curr_must_be_and_next(')');
do_block(plevel);
if (tk == T_ELSE) {
yylex(); p2 = gen_jmp(0); patch_jmp(pos);
do_block(plevel); patch_jmp(p2);
}
else patch_jmp(pos);
}
void do_expr() {
reuse_curr_tk = 1; expr::parse();
claim(tk == ',' || tk == ';' || tk == ')');
int n = expr::code.size();
memcpy(code + codetail, expr::code.c_str(), n), codetail += n;
}
uint do_test_expr() { do_expr(); return gen_je_or_jne(0, 0); }
%%
start : expr { code = $1; }
expr
: T_NUM { $$ = load_imm(tkval); }
| '"' { $$ = load_imm(tkval); } // such as 0x6804, address of "string"
| symbol { $$ = $1; }
| '(' expr ')' { $$ = $2; }
| '*' '(' T_CHAR '*' ')' expr { $$ = $6 + movsb_eax; }
| '-' expr { $$ = $2 + neg_eax; }
| expr '+' expr { $$ = $1 + push_eax + $3 + pop_ecx + add_ecx_eax; }
| expr '>' expr { $$ = $1 + push_eax + $3 + pop_ecx + cmp_and_set(setg); }
| expr T_OR expr { $$ = logical_and_or($1, $3, true); }
symbol : T_SYMBOL { $$ = load_local(symbols[tkval]); }
/*
2 || 3
10: b8 02 00 00 00 mov $0x2,%eax # x
15: 85 c0 test %eax,%eax
17: 0f 85 17 00 00 00 jne 0x34 # j
1d: b8 03 00 00 00 mov $0x3,%eax # y
22: 85 c0 test %eax,%eax
24: 0f 85 0a 00 00 00 jne 0x34 # j
2a: b8 00 00 00 00 mov $0x0,%eax # t(ail)
2f: e9 05 00 00 00 jmp 0x39 # jmp_5
34: b8 01 00 00 00 mov $0x1,%eax
*/
str logical_and_or(const str& a, const str& b, bool or_) {
str t = load_imm(or_ ? 0 : 1) + jmp_5 + load_imm(or_ ? 1 : 0);
str j = or_ ? jne : je;
str y = b + test_eax_eax + j + n2s(t.size() - 5) + t;
str x = a + test_eax_eax + j + n2s(y.size() - 5);
return x + y;
}

浙公网安备 33010602011771号