libc提供系统调用接口和程序的入口支持等。为了实现一个独立的程序,需要实现入口和系统调用。
先看源代码,nostd.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | #ifndef __NOSTD_H__#define __NOSTD_H____asm__ ( ".global _start\n\t" "_start:\n\t" "call main\n\t" "movl $1, %eax\n\t" "xorl %ebx, %ebx\n\t" "int $0x80\n\t");#define O_RDONLY 00#define O_WRONLY 01#define O_RDWR 02#define O_CREAT 0100#define O_EXCL 0200#define O_NOCTTY 0400#define O_TRUNC 01000#define O_APPEND 02000#define O_NONBLOCK 04000#define O_SYNC 04010000#define O_FSYNC O_SYNC#define O_ASYNC 020000// note: `naked` attribute is not supported on x86 archstatic int open(char *path, int flags, int mode){ __asm__ ( "pushl %ebx\n\t" "movl $0x05, %eax\n\t" "movl 8(%ebp), %ebx\n\t" "movl 12(%ebp), %ecx\n\t" "movl 16(%ebp), %edx\n\t" "int $0x80\n\t" "popl %ebx\n\t" );}static int write(int fd, const void *buf, int count){ __asm__ ( "pushl %ebx\n\t" "movl $0x04, %eax\n\t" "movl 8(%ebp), %ebx\n\t" "movl 12(%ebp), %ecx\n\t" "movl 16(%ebp), %edx\n\t" "int $0x80\n\t" "popl %ebx\n\t" );}static int read(int fd, void *buf, int count){ __asm__ ( "pushl %ebx\n\t" "movl $0x03, %eax\n\t" "movl 8(%ebp), %ebx\n\t" "movl 12(%ebp), %ecx\n\t" "movl 16(%ebp), %edx\n\t" "int $0x80\n\t" "popl %ebx\n\t" );}static int close(int fd){ __asm__ ( "pushl %ebx\n\t" "movl $0x06, %eax\n\t" "movl 8(%ebp), %ebx\n\t" "int $0x80\n\t" "popl %ebx\n\t" );}#endif |
这个头文件大部分是用汇编代码实现的,当然也可以用纯汇编文件,这里使用内联汇编。首先是函数外的汇编,如下:
1 2 3 4 5 6 7 8 | __asm__ ( ".global _start\n\t" "_start:\n\t" "call main\n\t" "movl $1, %eax\n\t" "xorl %ebx, %ebx\n\t" "int $0x80\n\t"); |
只有简单汇编才能放到函数外,这里和直接写在汇编文件中是一样的。上述代码定义一个全局符号_start。默认的链接脚本会使用_start符号作为入口点。
对应的汇编指令是调用main函数,接着调用sys_exit系统调用退出程序。
接下来就是open/read/write/close的系统调用,有了这几个接口,我们就能输出/输入数据到文件、tty设备等。在linux中一切设备皆文件。
这里需要注意的是函数里面的汇编不需要入口处的压栈和退出的ret。gcc会自动为函数添加。
和普通的hello有点不同,我们打开/dev/tty(当前终端)设备、写字符串,然后关闭。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include "nostd.h"int main(){ int ret; int fd = open("/dev/tty", O_WRONLY, 0); if (fd < 0) return 1; ret = write(fd, "hello\n", 6); if (ret < 0) return 2; close(fd); return 0;} |
当然直接写入文件描述符1(stdout)或者2(stderr)也是可以的。
编译命令:cc -m32 -nostdlib main.c
运行结果:
1 2 | herbert@Lenovo:/work/link/nostdlib$ ./a.outhello |