编译链接一个最小的C程序

在Linux下开发一般都会用到各种各样的库. 比如: 标准库(glibc), 其他第三方库等. 有的小伙伴可能好奇, 怎样开发一个不使用第三方库的程序呢? main函数是不是第一个执行的函数呢? 下面看一个例子, 以上的问题都能够有一个个明确的答案.

  • bar.c 文件
extern void foo(void);
int _start(void) {
    foo();
    return 0;
}

上面的函数_start是程序的入口, 为什么不是main函数呢? 其实程序的入口是可以通过gcc参数自定义的, 此处为_start函数. 而且自定义的程序入口点在linux下也不是程序执行的第一条代码. 之前还有程序二进制文件的加载代码, 动态链接库相关代码, bss段初始化代码等. 但如果是裸机代码, 自定义的程序入口点是程序执行的第一条代码.

  • foo.s 文件
.global foo
foo:
    movl $1, %eax       # write (
    movl $1, %edi       #   fd=1,
    movq $s, %rsi       #   buf=s,
    movl $(e-s), %edx   # count=e-s,
    syscall             # );

    movl $60, %eax      # exit (
    movl $1, %edi       #   status=1
    syscall             # );

s:
    .ascii "\033[01;31mHello, world\033[0m\n";
e:

上面代码的功能是: 通过系统调用将字符串输出到标准输出.

  • Makefile 文件
all: foobar

foobar: foo.o bar.o
    ld -e _start -o $@ $^

%.o: %.s
    as $< -o $@

clean:
    rm -f *.o foobar

上面的ld -e _start则定义了程序的入口点. 通过上面编译得到的可行文件是:

  • 静态程序
  • 没有连接任何库
  • 代码入口点不是main而是_start

如果觉得有帮助, 可以扫描右边的微信打赏码支持一下.

Leave a Reply

Your email address will not be published. Required fields are marked *