Linux C编译器从零开发一

基础程序汇编
test.c
cpp 复制代码
int main() {
  return 42;
}
查看反汇编
bash 复制代码
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, main

plus:

add rsi, rdi

mov rax, rsi

ret

main:

mov rdi, 3

mov rsi, 4

call plus

ret

.globl开头表示函数整个程序可见

call原理

  • call将下一条指令(在本例中)ret的地址推入堆栈
  • call跳转到作为参数给出的地址
自定义编译器编译基础程序
test.c
cpp 复制代码
#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;
}
编译运行
bash 复制代码
cc -o test test.c
./test 42 > test.s
cc -o tmp test.s
./tmp
echo $?
自定义编译器编译加减法程序
test.c
cpp 复制代码
#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;
}
编译
bash 复制代码
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
bash 复制代码
#!/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


创作不易,小小的支持一下吧!

相关推荐
caoerzhong几秒前
JeeWMS 开源 WMS 部署避坑指南:Java 仓库管理系统的环境基线、四类根因与可复现交付
java·开发语言·开源
时间的拾荒人3 分钟前
Qt 界面优化:绘图详解 —— 从基础图形到图片处理
开发语言·qt·面试
MayZork21 分钟前
Qt 文件操作:QSaveFile 与 QTemporaryFile(含 QTemporaryDir)实战
开发语言·qt
北冥you鱼33 分钟前
Go 语言空接口(interface{})使用场景与最佳实践
开发语言·windows·golang
xh didida43 分钟前
Linux -- 基础IO
linux·服务器·开发语言·c++
个 人 练 习 生1 小时前
C++ string 类模拟实现:从底层理解字符串(上)
开发语言·c++·经验分享·学习·程序人生
2601_966949651 小时前
多市场量化策略的数据接口应该如何设计:从数据层架构到策略接入
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
坤坤子吖1 小时前
C++智能指针:RAII、shared_ptr与内存泄漏
开发语言·c++·笔记·学习
奋斗的阿狸_19861 小时前
ESP32-S3 + ES7210 四通道麦克风录音上传方案
c语言·开发语言·fpga开发
weixin199701080162 小时前
《1688图片空间API踩坑:img.upload 与 album.* 的防盗链与CDN缓存问题》(附Python源码)
开发语言·python·缓存