当前位置: 首页 > news >正文

Linux C编译器从零开发一

基础程序汇编
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   rbp112e:	48 89 e5             	mov    rbp,rsp1131:	b8 2a 00 00 00       	mov    eax,0x2a1136:	5d                   	pop    rbp1137:	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
#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 || exitgcc -static -o tmp tmp.s./tmpactual="$?"if [ "$actual" = "$expected" ]; thenecho "$input => $actual"elseecho "$input => $expected expected, but got $actual"exit 1fi
}assert 0 0
assert 42 42
assert 21 '5+20-4'echo OK

参考

Compiler Explorer 


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

相关文章:

  • Web前端开发主题:深入探索、挑战与创新的四个维度
  • 机器 reboot 后 kubelet 目录凭空消失的灾难恢复
  • 文心智体 - 健身达人 | 一秒创建属于你的 “贾维斯“
  • 算法 | 剪枝函数以及几种形式回溯法和分支限界法的区别算法特性分支限界法的思想分支限界法的基本步骤Prim和Kruscal回溯法的效率
  • DELL服务器插入新磁盘、创建虚拟磁盘、挂载磁盘步骤
  • tcp协议机制的总结(可靠性,提高性能),基于tcp的应用层协议,用udp如何实现可靠传输
  • 系统编程:管道
  • 驱动开发(四):Linux内核中断
  • 【学习笔记】MySQL(Ⅲ)
  • 黑苹果睡眠总是自动唤醒(RTC)
  • JavaEE初阶--网络基本概念
  • 2024年宜春市中职“网络建设与运维”竞赛说明竞赛试题
  • 快速压缩前端项目
  • 【Windchill监听器、队列、排程】
  • is not null 、StringUtils.isNotEmpty和StringUtils.isNotBlank之间的区别?
  • 【React系列】如何构建React应用程序
  • 【前端学习】-粗谈选择器
  • 【跃迁之路】【641天】程序员高效学习方法论探索系列(实验阶段398-2018.11.14)...
  • 4. 路由到控制器 - Laravel从零开始教程
  • Git 使用集
  • js 实现textarea输入字数提示
  • JS变量作用域
  • leetcode46 Permutation 排列组合
  • MySQL几个简单SQL的优化
  • python 学习笔记 - Queue Pipes,进程间通讯
  • spring security oauth2 password授权模式
  • TCP拥塞控制
  • vue数据传递--我有特殊的实现技巧
  • 算法-插入排序
  • 微信端页面使用-webkit-box和绝对定位时,元素上移的问题
  • 我这样减少了26.5M Java内存!
  • 项目管理碎碎念系列之一:干系人管理
  • 一些css基础学习笔记
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • ​直流电和交流电有什么区别为什么这个时候又要变成直流电呢?交流转换到直流(整流器)直流变交流(逆变器)​
  • ​总结MySQL 的一些知识点:MySQL 选择数据库​
  • # windows 安装 mysql 显示 no packages found 解决方法
  • #快捷键# 大学四年我常用的软件快捷键大全,教你成为电脑高手!!
  • #每日一题合集#牛客JZ23-JZ33
  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切
  • (function(){})()的分步解析
  • (二)Pytorch快速搭建神经网络模型实现气温预测回归(代码+详细注解)
  • (非本人原创)史记·柴静列传(r4笔记第65天)
  • (附源码)spring boot建达集团公司平台 毕业设计 141538
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (六)激光线扫描-三维重建
  • (每日一问)基础知识:堆与栈的区别
  • (十六)视图变换 正交投影 透视投影
  • (一)SvelteKit教程:hello world
  • (转)Spring4.2.5+Hibernate4.3.11+Struts1.3.8集成方案一
  • ****** 二十三 ******、软设笔记【数据库】-数据操作-常用关系操作、关系运算
  • .config、Kconfig、***_defconfig之间的关系和工作原理
  • .jks文件(JAVA KeyStore)
  • .NET Core IdentityServer4实战-开篇介绍与规划
  • .Net Core 微服务之Consul(三)-KV存储分布式锁