基础程序汇编
test.c
int main() {
return 42;
}
查看反汇编
cc -o test test.c
objdump -d -M intel test
0000000000001129 <main>:
1129: f3 0f 1e fa endbr64
112d: 55 push rbp
112e: 48 89 e5 mov rbp,rsp
1131: b8 2a 00 00 00 mov eax,0x2a
1136: 5d pop rbp
1137: c3 ret
函数参数汇编
test.c
int plus(int x, int y) {
return x + y;
}int main() {
return plus(3, 4);
}.intel_syntax noprefix
.globl plus, mainplus:
add rsi, rdi
mov rax, rsi
retmain:
mov rdi, 3
mov rsi, 4
call plus
ret
.globl开头表示函数整个程序可见
call原理
- call将下一条指令(在本例中)ret的地址推入堆栈
- call跳转到作为参数给出的地址
自定义编译器编译基础程序
test.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "Please input a Number:\n");
return 1;
}
printf(".intel_syntax noprefix\n");
printf(".globl main\n");
printf("main:\n");
printf(" mov rax, %d\n", atoi(argv[1]));
printf(" ret\n");
return 0;
}
编译运行
cc -o test test.c
./test 42 > test.s
cc -o tmp test.s
./tmp
echo $?
自定义编译器编译加减法程序
test.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "Please input a Number\n");
return 1;
}
char *p = argv[1];
printf(".intel_syntax noprefix\n");
printf(".globl main\n");
printf("main:\n");
printf(" mov rax, %ld\n", strtol(p, &p, 10));
// strtol读取数字,读完自动跳到下个符号
while (*p) {
if (*p == '+') {
p++;
printf(" add rax, %ld\n", strtol(p, &p, 10));
continue;
}
if (*p == '-') {
p++;
printf(" sub rax, %ld\n", strtol(p, &p, 10));
continue;
}
fprintf(stderr, "illegal sign '%c'\n", *p);
return 1;
}
printf(" ret\n");
return 0;
}
编译
cc -o test test.c
./test 12+3+4 > tmp.s
cc -o tmp tmp.s
./tmp
echo $?
./test 1*3 > tmp.s //会提示非法符号
测试
test.sh
#!/bin/bash
assert() {
expected="$1"
input="$2"
./chibicc "$input" > tmp.s || exit
gcc -static -o tmp tmp.s
./tmp
actual="$?"
if [ "$actual" = "$expected" ]; then
echo "$input => $actual"
else
echo "$input => $expected expected, but got $actual"
exit 1
fi
}
assert 0 0
assert 42 42
assert 21 '5+20-4'
echo OK
参考
Compiler Explorer