GNU链接脚本(12) - 抛弃glibc依赖

原文:https://github.com/iDalink/ld-linker-script/tree/master/12%20%E6%8A%9B%E5%BC%83glibc%E4%BE%9D%E8%B5%96

1、目标

上一节,我们已经体会到系统库的复杂。为了保持可控性,我们决定抛弃glibc,构建一个完全可控的应用程序。我们需要两个函数,putsexit,分别实现日志输出和程序退出。

2、系统调用

应用程序调用系统服务称之为系统调用(system call),应用程序之间的函数调用称之为库调用(library call)。x86的系统调用指令为int $0x80。x86-64架构的系统调用指令为syscall,系统调用返回指令为sysret指令。关于该指令的详细细节不再赘述。

下面给出putsexit的汇编代码。

SYSCALL_NO_WRITE  =  1
SYSCALL_NO_EXIT   = 60

    .text
    .code64
    
    .global write
write:
    mov $SYSCALL_NO_WRITE, %rax
    syscall
    ret
    
    .global exit
exit:
    mov $SYSCALL_NO_EXIT, %rax
    syscall
    ret

3、链接

        为了简单起见,我们首先以静态方式链接系统调用函数。链接命令不再需要指定glibc的一串依赖,链接脚本也不再需要指出plt段。链接命令和链接脚本如下。测试代码位于01目录。

ld -static -T linker_script.lds -e main -o app $^

ENTRY(_start)
SECTIONS
{
  . = 0;
  .text . : { *(.text) }
  .data . : { *(.data)}
  .bss : { *(.bss) }
}

        可以看出应用程序的运行时结构十分精简。

4、构建标准库antlibc

        我们决定将前一小节的两个系统调用函数构造成自己的libc,并把它取名为antlibc。理论上来说,只需要将其编译为动态链接库(so)即可。方便起见,我们的动态链接库interpreter采用glibc提供的/lib64/ld-linux-x86-64.so.2

        Makefile文件如下。完整代码位于02目录。该示例编译syscall.olibantlibc.so。主程序app依赖libantlibc.so

test:app
	readelf -l app
	export LD_LIBRARY_PATH=.
	./app

app:main.o libantlibc.so linker_script.lds Makefile
	ld -T linker_script.lds -dynamic-linker /lib64/ld-linux-x86-64.so.2 -L. -e main -o app main.o -lantlibc

main.o:main.c
	gcc -g -c -o $@ $<

libantlibc.so:syscall.o
	ld -shared -o $@ $^
	readelf -l $@

syscall.o:syscall.S
	as -o $@ $<

        注意,我们的so库位于当前目录下,运行程序时需要将当前目录加入到链接库搜索路径中,命令为export LD_LIBRARY_PATH=.。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值