本文目的是写出在Linux x86_64下的Hello world程序,要求:不使用libc库,支持传入命令行参数、返回结果,并且极可能小。
实现方案使用了简化的 _start 入口函数启动main函数,使用 write系统调用实现输出字符串功能。
//lib.h
#ifndef LIB_H
#define LIB_H
void print(const char *);
#endif
//hello.c
#include "lib.h"
int main(int argc,char * argv[])
{
char *str = "Hello World!\n";
int i;
if(argc > 1) {
for (i = 1; i < argc; i++) {
print(argv[i]);
print(" ");
}
print("\n");
} else {
print(str);
}
return 1;
}
print.c 文件
//print.c
#include "lib.h"
#include <unistd.h>
#include <syscall.h>
extern long syscall3(long arg1, long arg2, long arg3, long number);
// __NR_write is 1 in x86_64 linux.
#define write(arg1, arg2, arg3) syscall3((long)arg1, (long)arg2, (long)arg3, (long) __NR_write)
long _strlen(const char *buf)
{
long len = 0;
while(*buf++) len++;
return len;
}
void print(const char *str)
{
//STDOUT_FILENO is 1
(void) write(STDOUT_FILENO, str, _strlen(str));
}
sys_call.S
.global syscall3
# long syscall3(long arg1, long arg2, long arg3, long number);
# system call with 3 arguments.
# edi: first argument
# rsi: second argument
# rdx: third argument
# rcx: forth argument, the system call number. x86_64
syscall3:
movq %rcx, %rax # rax register's used to indicate the system call number, and it's used to return the system call result.
syscall
ret
stubstart.S
.globl _start
_start:
movq (%rsp), %rdi #argc
leaq 8(%rsp), %rsi #argv
call main
movq %rax, %rdi #main return value
movq $60, %rax #call sys_exit
syscall
#Makefile
hello: hello.c print.c stubstart.S sys_call.S
gcc -o hello -static -nostartfiles -nodefaultlibs -nostdlib -Wall hello.c print.c stubstart.S sys_call.S
strip hello
clean:
rm hello
运行结果:
[root@localhost minihello]# ./hello my own HELLO WORLD!
my own HELLO WORLD!
[root@localhost minihello]# ./hello
Hello World!