不适用库函数打印HelloWorld(改编)
2019年8月29日
一般来说,使用
printf()
库函数能够很方便得打印出helloworld,这里介绍一种不适用库函数打印出helloworld的方法。
代码如下 (注意:不可在wsl系统下运行)
char *str = "Hello world!\n";
void print(){
asm(
"movl $13,%%edx \n\t"
"movl $0,%%ecx \n\t"
"movl $0,%%ebx \n\t"
"movl $4,%%eax \n\t"
"int $0x80 \n\t"
::"r"(str):"edx","ecx","ebx"
);
}
void exit(){
asm(
"movl $42,%ebx \n\t"
"movl $1,%eax \n\t"
"int $0x80"
);
}
void nomain(){
print();
exit();
}
首先一般函数的入口在库的
_start
,由库负责初始化后调用
main
函数来执行程序的主体部分。这里使用我们自己定义的
nomain
作为程序的入口。
这里的
print
函数调用了linux系统的
write
系统调用,
exit
调用了linux系统的
EXIT
系统调用。同时,这里使用了GCC的内嵌汇编。代码中的系统调用通过0x80实现,其中eax为调用号,ebx,ecx,edx等通用寄存器用来传递参数。write调用是一个往文件句柄写入数据,用C语言描述为:
int write(int filedesc,char* buffer,int size);
write调用的调用号为4,则eax=0。
filedesc表示被写入的文件句柄,使用ebx寄存器传递,我们这里是要往默认终端(stdout)输出,它的文件句柄为0,即ebx=0。
buffer为要写入的缓冲区地址,使用ecx寄存器传递,我们这里要输出字符串str,所以ecx=str。
size表示要写入的字节数,使用edx寄存器传递,字符串“Hello wrld!\n”长度为13字节,所以edx=13。
EXIT的系统调用的调用号为1,即eax=1。
编译指令为
gcc -c -fno-builtin xxx.c
ld -static -e nomain -o xxx xxx.o
第一步编译出.o文件,再使用ld将.o文件链接成可执行文件
-fno-builtin GCC会把把C库函数替换成编译器的内置函数来进行优化,这里这个指令关闭这个替换功能。
-static 使用静态链接的方式来进行链接
-e nomain 表示程序的入口函数为nomain
Previous
一个简单的爬取csdn博客图片的爬虫
Newer