今天看到一个很有意思的小程序,它让我对Linux下C程序的编译链接有了一个全新的认识!

这个程序的就是写一个简单的输出“hello World!”:

  要求:1.不使用C运行库,写一个独立于任何库的程序。(也就是说我们不能#include<stdio>)。

      2.不适用main函数为程序的入口(大家都知道一般使用了库的程序都是使用main函数作为程序的入口,在这里我们使用自己写的函数nomain作为程序的入口)。

      3.使用连接器ld把程序的所有段合为一个“Tinytext”段。

  显然要符合要求我们就只能用汇编去写,源代码如下:

char *str="Hello world!\n";void print()
{asm("movq $13,%%rdx \n\t""movq %0,%%rcx \n\t""movq $0,%%rbx \n\t""movq $4,%%rax \n\t""int $0x80     \n\t"::"r"(str):"edx","ecx","ebx");
}void exit()
{asm("movq $42,%rbx   \n\t""movq $1,%rax    \n\t""int $0x80       \n\t");
}void nomain()
{print();exit();
}

我们vi一个TinyHelloWorld.c。里面写上如上代码。

本人的环境是64位的,如果是32为环境的朋友只要把,movq改为movl,rdx改为edx,rax改为eax,rbx改为ebx。

由于操作系统的系统结构发生了变化,在x86-64中,所有通用寄存器(GPRs)都从32位扩充到了64位,名字也发生了变化。8个通用寄存器(eax, ebx, ecx, edx, ebp, esp, esi, edi)在新的结构中被命名为rax, rbx, rcx, rdx, rbp, rsp, rsi, rdi。movl命令也需相应改成movq

首先程序的入口时nomain函数,它调用print函数打印HelloWorld,然后调用exit函数退出。print函数使用了Linux的WRITE系统调用,exit函数使用了EXIT系统调用。

定义一个字符串,它是放在只读代码段的。

print函数和exit函数中,WRITE系统调用和EXIT系统调用都是通过0x80中断实现的。其中eax为调用号rbx,rcx,rdx是一些寄存器用来传递参数的。比如WRITE系统调用是往一个文件句柄写入数据,如果用C语言来表示WRITE系统调用的话他的函数原型是:

int write(int filedesc,char* buffer,int size)
  • WRITE的调用号为4,则rax为0。

  • filedesc表示被写入的句柄文件,我们默认输出为默认终端,他的句柄为0,所以rbx为0。

  • buffer表示要写入的缓冲区地址使用rcx寄存器传送,我们要输出str字符串,所以rcx=str。

  • size表示要写入的字节数,这里str的长度为13字节,所以rdx=13。

代码写好以后我们使用普通的命令行来编译链接TinyHelloWorld.c

gcc -c -fno-builtin TinyHelloWorld.c  //生成TinyHelloWorld.o
  • -c参数是表示编译。

  • -fno-builtin参数关闭GCC内置函数的功能(GCC中有很多内置的函数,它你会把C库的一些函数替换成内置的函数,以达到优化的功能)

    然后链接TinyHelloWorld.o文件生成可执行文件TinyHelloWorld.

ld -static -e nomain -o TinyHelloWorld TinyHelloWorld.o

至此,一个HelloWorld程序写好了。

我们使用objdump指令来查看TinyHelloWorld这个文件可以看出来他又4个段:.data .rodata .text .commond 段。这几个段的属性都是只读的,按理来说我们可以把他们合围一个段。这就需要借助ld链接器来实现。

objdump -h TinyHelloWorld

使用-verbose查看默认的链接脚本信息:

ld -verbose TinyHelloWorld

然后编写TinyHelloWorld.lds脚本:

ENTRY(nomain)SECTIONS
{.= 0x08048000 + SIZEOF_HEADERS;tinytext : { *(.text) *(.data) *(.rodata)}/DISCARD/ :{ *(.comment) }
}

然后使用自己编写的脚本链接目标文件。

gcc -c -fno-builtin TinyHelloWorld.
ld -static -T TinyHelloWorld.lds -o TinyHello TinyHelloWorld.o

-static -T TinyHelloWorld.lds参数是使用静态链接,并且使用自己编写的TinyHelloWorld.lds脚本链接。

它会生成一个588个字节的可执行文件TinyHelloWorld。执行可以打印Hello World!。如果你使用objdump查看TinyHelloWorld的段,你会发现我们达到了将最后一个只有一个段的要求。

转载于:https://blog.51cto.com/helloleex/1774383

Linux下C程序的链接过程相关推荐

  1. linux连接到程序,Linux下C程序的链接过程

    今天看到一个很有意思的小程序,它让我对Linux下C程序的编译链接有了一个全新的认识! 这个程序的就是写一个简单的输出"hello World!": 要求:1.不使用C运行库,写一 ...

  2. linux 跟踪程序执行过程,用pvtrace和Graphviz实现对linux下C程序的函数调用跟踪

    用pvtrace和Graphviz实现对linux下C程序的函数调用跟踪 用pvtrace和Graphviz实现对linux下C程序的函数调用跟踪 1:功能介绍,使用本方法可以实现linux下C应用程 ...

  3. Linux下C程序的编辑,编译和运行以及调试

                                                                                                        ...

  4. qt调用linux 进程,Linux 下qt 程序打包发布(使用linuxdelpoyqt ,shell 脚本)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/u014746574/article/d ...

  5. Linux下C程序的可扩展性.

    What I write, what I lose. 以下为个人关于Linux下C程序的可扩张性的一点想法. 可扩展性的应用场景: 1. 有两个项目都需要使用的一个相同功能的程序, 但是有些要求不一样 ...

  6. linux下安装nginx启动,Linux下安装启动nginx的过程

    1.首先将nginx的安装包传到虚拟机里的/home目录下 2.为了方便nginx运行而不影响linux安全需创建组合用户 groupadd -r nginx useradd -r -g nginx  ...

  7. Linux下Java程序中文乱码问题研究

    Linux下Java程序中文乱码问题研究 摘  要:在一个项目的开发中,我用linux内核源代码和busybox源代码自己编译打造的操作系统mylinux 1.0 ,服务器是我用java语言自己编写的 ...

  8. Linux 下qt 程序打包发布(使用linuxdelpoyqt ,shell 脚本)

    Linux 下qt 程序打包发布(使用linuxdelpoyqt ,shell 脚本) 转载于:https://www.cnblogs.com/zhehan54/p/9549017.html

  9. linux c++ 程序运行时间,总结UNIX/LINUX下C++程序计时的方法

    前言 良好的计时器可帮助程序开发人员确定程序的性能瓶颈,或对不同算法进行性能比较.但要精确测量程序的运行时间并不容易,因为进程切换.中断.共享的多用户.网络流量.高速缓存访问及转移预测等因素都会对程序 ...

最新文章

  1. 触发transition的几种方式--转
  2. 认识AndEngine选自Android 2D游戏引擎AndEngine快速入门教程
  3. Netty学习笔记(二) 实现服务端和客户端
  4. Person Re-Identification by Multi-Channel Parts-Based CNN with Improved Triplet Loss Function
  5. is running beyond the ‘VIRTUAL‘ memory limit. Current usage: 123.5 MB of 1 GB physical memory used
  6. html获取微信code,get-weixin-code.html
  7. HNOI2004 郁闷的出纳员(Splay)
  8. Spring3.0核心组件的源码简单分析
  9. vmware fusion 7 序列号
  10. 工行u盾显示316_工行手机银行u盾签名失败或未完成(310)是为什么?
  11. GitLab Admin Area
  12. 关于数据库可变长字符串类型长度设计问题:慷慨是不明智的
  13. 40 个超棒的免费 Bootstrap HTML5 网站模板
  14. centos c++ mysql_腾讯云Linux CentOS C++连接MySQL
  15. LINK : fatal error LNK1168: cannot open Debug/xxx.exe for writing
  16. 任正非 采访 安卓 鸿蒙,法媒专访任正非透露“鸿蒙”系统“很可能”快过安卓...
  17. java用数组显示周期性波形,常见的周期性变化波形有正弦波、三角波和矩形波。...
  18. 推荐系统在美团综合业务中的应用及实践
  19. 使用IDEA运行OnlyOffice的Java示例
  20. 广西大学计算机仿真实验,计算机仿真(matlb)实验一(广西大学电气).doc

热门文章

  1. C++与Java多态的区别
  2. MySQL事务以及加锁机制
  3. Oracle数据库文件恢复与备份思路
  4. 高 star 开源项目来实验楼啦,深度学习强推教材
  5. Nacos源码覆盖实例列表
  6. SpringSecurity注销功能
  7. 使用JUnit 5 执行条件和并发测试
  8. HTTPS证书的申请过程
  9. 微信支付 - 构建商户端支付成功的回调接口
  10. EasyExcel读写Excel的基本使用