LLVM Cpu0 新后端5 静态重定位 动态重定位

LLVM后端开发实战

 想好好熟悉一下llvm开发一个新后端都要干什么,于是参考了老师的系列文章:

LLVM 后端实践笔记

代码在这里(还没来得及准备,先用网盘暂存一下):

链接: https://pan.baidu.com/s/1yLAtXs9XwtyEzYSlDCSlqw?pwd=vd6s 提取码: vd6s 

目录

一、准备知识

1.1 链接器与编译器

1.2 静态重定位

1.3 动态重定位

二、修改的文件

2.1 Cpu0AsmPrinter.cpp

2.2 Cpu0ISelDAGToDAG.cpp/.h

2.3 Cpu0ISelLowering.cpp/.h

2.4 Cpu0InstrInfo.td

2.5 Cpu0MCInstLower.cpp/.h

2.6 Cpu0MachineFunctionInfo.cpp/.h

2.7 Cpu0RegisterInfo.cpp

2.8 Cpu0Subtarget.cpp/.h

2.9 Cpu0TargetObjectFile.cpp/.h

2.10 MCTargetDesc/Cpu0BaseInfo.h

三、修改后的效果

3.1 static模式

3.2 static small section模式

3.3 dynamic模式

3.4 dynamic small section模式


一、准备知识

1.1 链接器与编译器

首先,显而易见链接器和编译器肯定不是一个东西。编译器的作用是中端优化以及后端转化成目标架构相关的汇编文件或者目标文件,到这里编译器就算是完成了他的工作了。之后就需要链接器了,链接器的作用是将生成的目标文件与其他的应用库和系统库一起链接成可执行文件,传统链接器在这一过程中主要做了两个工作,一是段合并,链接器会将不同文件的相似段进行合并,另一个就是符号重定位,链接器会对文件进行第二次扫描,利用第一次扫描的符号表信息,对符号引用地址的地方进行地址的更新,这个就是符号的解析以及重定位过程。

注意,这里我们说的是传统链接器,因为现在的链接器都支持LTO(链接时优化),其实相当于将编译器部分的一些中端优化和后端的工作在链接阶段做,链接阶段所需的所有文件是可见的,因此能够在一个更高的视野上做一个全局的优化,所以现代链接器的功能绝不仅仅是上述两点。

本章是做Cpu0架构重定位的适配,因此本章简单介绍一下当前linux系统上的两种重定位机制。我们用下边的这个例子:

# extern.c
int extern_aaa = 555;
int extern_func() {
  return 666;
}

#test.c
extern int extern_aaa;
int global_bbb = 111;
static int static_ccc = 222;
extern int extern_func();
int global_func() {
  return 333;
}
static int static_func() {
  return 444;
}
int main() {
  int ddd1 = extern_aaa;
  int ddd2 = global_bbb;
  int ddd3 = static_ccc;
  int ddd4 = extern_func();
  int ddd5 = global_func();
  int ddd6 = static_func();
  return 0;
}

1.2 静态重定位

静态重定位一般由操作系统中的重定位装入程序完成。重定位装入程序根据当前内存的分配情况,按照分配区域的起始地址逐一调整目标程序指令中的地址部分。目标程序在经过重定位装入程序加工之后,不仅进入到分配给自己的绝对地址空间中,而且程序指令中的地址部分全部进行了修正,反映出了自己正确的存储位置,保证了程序的正确运行。

特点:即在程序装入内存的过程中完成,是指在程序开始运行前,程序中的各个地址有关的项均已完成重定位,地址变换通常是在装入时一次完成的,以后不再改变,故成为静态重定位。

优点:无需硬件支持。

缺点:程序重定位之后就不能在内存中搬动了;要求程序的存储空间是连续的,不能把程序放在若干个不连续的区域中。

clang -fno-PIC -g -c extern.c -o extern.o
clang -fno-PIC -g -c test.c -o test.o
clang -no-pie -g extern.o test.o -o test.out

clang默认是使用动态重定位的,因此我们使用no-pic选项来关闭PIC,同时打开-g选项方便我们看到更多的符号以及调试,我的机器的clang版本是15,不同版本的clang可能会有一些区别。

首先我们先通过objdump -d命令先看一下test.o中的内容

test.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <global_func>:
   0:	55                   	push   %rbp
   1:	48 89 e5             	mov    %rsp,%rbp
   4:	b8 4d 01 00 00       	mov    $0x14d,%eax
   9:	5d                   	pop    %rbp
   a:	c3                   	retq
   b:	0f 1f 44 00 00       	nopl   0x0(%rax,%rax,1)

0000000000000010 <main>:
  10:	55                   	push   %rbp
  11:	48 89 e5             	mov    %rsp,%rbp
  14:	48 83 ec 20          	sub    $0x20,%rsp
  18:	c7 45 fc 00 00 00 00 	movl   $0x0,-0x4(%rbp)
  1f:	8b 04 25 00 00 00 00 	mov    0x0,%eax
  26:	89 45 f8             	mov    %eax,-0x8(%rbp)
  29:	8b 04 25 00 00 00 00 	mov    0x0,%eax
  30:	89 45 f4             	mov    %eax,-0xc(%rbp)
  33:	8b 04 25 00 00 00 00 	mov    0x0,%eax
  3a:	89 45 f0             	mov    %eax,-0x10(%rbp)
  3d:	b0 00                	mov    $0x0,%al
  3f:	e8 00 00 00 00       	callq  44 <main+0x34>
  44:	89 45 ec             	mov    %eax,-0x14(%rbp)
  47:	e8 00 00 00 00       	callq  4c <main+0x3c>
  4c:	89 45 e8             	mov    %eax,-0x18(%rbp)
  4f:	e8 1c 00 00 00       	callq  70 <static_func>
  54:	89 45 e4             	mov    %eax,-0x1c(%rbp)
  57:	8b 45 f8             	mov    -0x8(%rbp),%eax
  5a:	03 45 f4             	add    -0xc(%rbp),%eax
  5d:	03 45 f0             	add    -0x10(%rbp),%eax
  60:	03 45 ec             	add    -0x14(%rbp),%eax
  63:	03 45 e8             	add    -0x18(%rbp),%eax
  66:	03 45 e4             	add    -0x1c(%rbp),%eax
  69:	48 83 c4 20          	add    $0x20,%rsp
  6d:	5d                   	pop    %rbp
  6e:	c3                   	retq
  6f:	90                   	nop

0000000000000070 <static_func>:
  70:	55                   	push   %rbp
  71:	48 89 e5             	mov    %rsp,%rbp
  74:	b8 bc 01 00 00       	mov    $0x1bc,%eax
  79:	5d                   	pop    %rbp
  7a:	c3                   	retq

1f、29、33三条指令就是对于extern_aaa、global_bbb、static_ccc三个变量的调用,我们能够看到当前是用0来占位的。我们能够看到他们最终都被存到了rbp寄存器一定偏移的栈中了,因此局部变量通过当前函数栈桢的基地址(rbp)就可以直接拿到,不存在重定

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值