[008]C/C++系列 | 最小的程序 不一样的HelloWorld!!!

一、需求

  1.  日常的HelloWorld打印,需要用到C语言库里面的函数(printf),我们希望“小程序”脱离C语言库,使它成为一个独立于任何库的纯正“程序”

  2. 日常使用的程序,都是以main作为入口,现在我们自定义一个入口(nomain)

  3. 日常的HelloWorld会产生很多段,现在我们需要将所有的段合并到"tinytext"段

二、实现

2.1GCC内嵌汇编

int write(int filedesc, char* buffer, int size); 函数实现!!!

  • WRITE 调用号为4
  • filedesc表示被写入文件句柄,使用ebx寄存器传递,这里我们需要默认终端输出,它的句柄为0,ebx = 0
  • buffer表示要写入缓冲区地址,使用ecx寄存器传递,我们这里要输出字符串str,所以ecx = str
  • size 表示写入的字节数,使用edx寄存器传递,字符串str的长度为13, 所以edx = 13
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");
}

2.2结束进程

  • ebx 表示进程退出码(Exit Code)

  • EXIT系统调用的调用号为1,即eax = 1

void
exit()
{
    asm( "movl $42, %ebx  \n\t"
         "movl $1, %eax \n\t"   
         "int $0x80  \n\t");
}

备注:

 当执行完程序之后,如果想打印程序执行的退出码,可以这样子操作:

$ echo $?

 三、实现


/*
 * ld.c
 * Copyright (C) 2020 root <root@tw.com>
 *
 * Distributed under terms of the MIT license.
 */

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  \n\t");
}

void 
nomain()
{
    print();
    exit();
} 

四、编译&链接

$ gcc -c -fno-builtin  ld.c
$ ld -static -e nomain -o ld ld.o

4.1常见错误

原因:

在64位系统下去编译32位的目标文件,这样是非法的。

解决办法:

用”-m32”强制用32位ABI去编译

$ gcc -c -fno-builtin -m32 ld.c

 

4.2 链接错误

原因:

目标文件`ld.o’是32位系统的,在x86_64平台下默认链接用的是elf_x86_64.x,链接32位可执行文件使用的是elf32_x86_64.x

解决办法:

$ ld -static -m elf_i386 -e nomain -o ld ld.o

 

五、执行

 

六、改进

将多个端合并为一个段 !!!

 // ld.lds

ENTRY(nomain)

SECTIONS
{
    . = 0x08048000 + SIZEOF_HEADERS;
    tinytext : { *(.text) *(.data) *(.rodata) }
    /DISCARD/ : { *(.comment) }
}                                                                                                                   
  • ENTRY()指定程序入口
  • SECTIONS链接脚本主体
    • . = 0x08048000 + SIZEOF_HEADERS; . 表示当前虚拟地址;SIZEOF_HEADERS;为输出文件的文件头大小。 这里表示 将当前的虚拟地址设置成0x08048000 + SIZEOF_HEADERS 。  因为这条语句后面紧跟着输出段"tinytext",所以此段虚拟地址即为:0x08048000 + SIZEOF_HEADERS
    • tinytext : 转换规则。表示合并到tinytext
    • /DISCARD/ 丢弃.comment段
$ ld -static -T ld.lds -m elf_i386 -o ld ld.o

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值