不一样的hello world

迷南。 2022-10-26 03:55 264阅读 0赞

一. 简介

  最近学习了一些C内联汇编的知识,简单的尝试了一下,发现里面有很多有趣的东西,分享如下。首先说明,本文的内联使用仅为一个小例子,并不规范,另外32位和64位有着较大区别,本文基于64位Ubuntu16.04环境编译。

二. 源码介绍

  代码本身很简单,包括了三个函数,分别用于打印,退出以及作为函数入口,实际效果为输出Hello world

2.1 print()

  打印函数printf()本身其实是调用了write()函数(也可以调用puts()等),这里通过80中断直接调用write()对应的系统调用。write()的API如下所示

  1. int write(int fd, char *buffer, int size);
  • 由于系统调用号(查中断标可得)为4,所以直接传递给rax赋值4即可。
  • fd即文件描述符,这里使用标准输出,即stdout,所以fd为0,rbx赋值为0
  • buffer即文件缓冲区,这里就是str字符串,使用rcx传递,赋值为地址对应的变量即0地址
  • size表示的时文件字节数,这里是13字节,因此rdx赋值为13

2.2 exit()

  exit()对应的系统调用为exit(),系统调用号为1,所以rax赋值为1。rbx表示返回值,这里42其实是一个神奇的数字,有兴趣的可以看一看《银河系漫游指南》(大雾)。

  1. //hello.c
  2. char* str = "Hello world!\n";
  3. void print()
  4. {
  5. asm(
  6. "mov $13, %%rdx \n\t"
  7. "mov %0, %%rcx \n\t"
  8. "mov $0, %%rbx \n\t"
  9. "mov $4, %%rax \n\t"
  10. "int $0x80 \n\t"
  11. ::"r"(str):"rdx","rcx","rbx");
  12. }
  13. void exit()
  14. {
  15. asm(
  16. "mov $42, %rbx \n\t"
  17. "mov $1, %rax \n\t"
  18. "int $0x80 \n\t"
  19. );
  20. }
  21. void hello()
  22. {
  23. print();
  24. exit();
  25. }

  注意,本代码为64位编译环境,如果是32位需要改为movl配合ebx/ecx系列或者编译时加上-m32选项。

三. 编译和执行

  使用如下命令编译和链接,生成可执行文件。这里-fno-builtin表示不进行编译器优化。否则对于纯字符串的printf(),编译器会自动优化为使用puts()函数。另外链接时,-e hello表示入口函数为hello(),而非常见的main()函数。

  1. gcc -c -fno-builtin hello.c
  2. ld -static -e hello -o hello hello.o

  运行hello可见如下结果,输出成功,返回值为预设的42。

  1. $ ./hello
  2. Hello world!
  3. $ echo $?
  4. 42

四. 自制lds

  通过objdump可以看到hello包括了.data, .text, .rodata等字段,同时还有.comment。这里我们尝试自己制作链接脚本,使这三个字段合并,同时去掉.comment字段,这样子应该可以让可执行文件的大小大大缩减。

  • ENTRY表明了入口函数为hello函数

    ENTRY(hello)

    SECTIONS
    {

    1. . = 0X00000000 + SIZEOF_HEADERS;
    2. tinytext : {*(.text) *(.data) *(.rodata)}
    3. /DISCARD/ : {*(.comment)}

    }

  再次编译

  1. ld -static -T hello.lds -o hello hello.o

  编译完依然可以正常执行,通过objdump可见已经生效,可执行文件的大小从1.6KB成功缩减到704B,所以就算是成功了。实际还可以通过-s再次减小大小。

总结

  本文基于中断,汇编,编译,链接等知识,进行一次综合性的上手小实验,适合新人们做为入门级小尝试来步入学习。另外内联汇编本身较为复杂,本文进行了大量简化,实际在源码及工业级运用会需要考虑更多的安全性等因素,同时80中断实际并不适合在64位使用,这个回头会再写一篇文章专门叙述。鉴于水平有限,还望大佬们多多指点不足之处,共同进步。

#

发表评论

表情:
评论列表 (有 0 条评论,264人围观)

还没有评论,来说两句吧...

相关阅读

    相关 一样hello world

    一. 简介   最近学习了一些C内联汇编的知识,简单的尝试了一下,发现里面有很多有趣的东西,分享如下。首先说明,本文的内联使用仅为一个小例子,并不规范,另外32位和64位

    相关 Hello World

    Hello World 一、简述          简单的Hello World程序。(时间久了就会忘,趁着还有印象先记下)     1、C语言:  控制台程序、有窗体

    相关 Hello World

    这是我的第一篇博客,虽然是第一次写博客,但是之前也在微信公众号上写过一些文章(虽然没有阅读量),或多或少对自己产生了一定的帮助。 这些天会考虑将其中一些较为有意义的