未分类

不适用库函数打印HelloWorld(改编)

一般来说,使用

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

Leave a Reply

邮箱地址不会被公开。 必填项已用*标注