原文链接

关于ld命令,网上资料不多,流传的有ld的中文手册,不过那手册不是给人看的,至少不是给新手看的,太难理解了。

背景交待:

1、将gcc与ld命令分开执行以生成可执行文件;

2、回归经典,在屏幕上打印“Hello World!”;

main.c内容:

#include <stdio.h>

int main(void)
{
    printf("hello from %s(). \n", __func__);
    return 0;
}

编译生成main.o文件:

[latelee@FightNow lib-test]$ gcc -c main.c

链接:

[latelee@FightNow lib-test]$ ld main.o 
ld: warning: cannot find entry symbol _start ; defaulting to 08048074 
main.o: In function `main':
main.c:(.text+0x21): undefined reference to `printf'

现在解决第一个warning,使用-e指定入口函数(地址):

[latelee@FightNow lib-test]$ ld -e main main.o 
main.o: In function `main':
main.c:(.text+0x21): undefined reference to `printf'

因为printf定义于C库中,因此需要使用C库:

[latelee@FightNow lib-test]$ ld -e main main.o -lc 
(默认为动态库)

执行之,可惜出错了:

[latelee@FightNow lib-test]$ ./a.out 
-bash: ./a.out: /usr/lib/libc.so.1: bad ELF interpreter: 没有那个文件或目录

它说“没有那个文件或目录”,查看一下:

[latelee@FightNow lib-test]$ ls /usr/lib/ | grep "libc.so" 
libc.so

的确没有,不过我们可以无中生有制作一个(网上有此说法,创建符号连接文件):

[root@FightNow lib-test]# ln -s /usr/lib/libc.so  /usr/lib/libc.so.1 

[root@FightNow lib-test]# ls /usr/lib/ | grep "libc.so" 
libc.so
libc.so.1
[root@FightNow lib-test]# ls -l /usr/lib/ | grep "libc.so" 
-rw-r--r--  1 root root      238 2008-07-17 libc.so
lrwxrwxrwx  1 root root       16 03-24 14:31 libc.so.1 -> /usr/lib/libc.so

再次执行:

[root@FightNow lib-test]# ./a.out  
bash: ./a.out: 权限不够

还是不行,我都使用root来执行了还说权限不够,此路不通。

前面默认是使用动态C库的(静态库与动态库同名时,优先使用动态库),下面使用C静态库再编译一次:

[latelee@FightNow lib-test]$ ld -e main main.o /usr/lib/libc.a 
/usr/lib/libc.a(syslog.o): In function `closelog': 
(.text+0xcd): undefined reference to `_Unwind_Resume'
/usr/lib/libc.a(syslog.o): In function `openlog': 
(.text+0x3d2): undefined reference to `_Unwind_Resume'
/usr/lib/libc.a(syslog.o): In function `__vsyslog_chk': 
(.text+0x908): undefined reference to `_Unwind_Resume'
/usr/lib/libc.a(syslog.o): In function `__vsyslog_chk': 
(.text+0x91a): undefined reference to `_Unwind_Resume'
.
.
.
/usr/lib/libc.a(iofclose.o): In function `fclose': 
(.text+0x1a7): undefined reference to `_Unwind_Resume'
/usr/lib/libc.a(iofclose.o):(.eh_frame+0x166): undefined reference to `__gcc_personality_v0'
/usr/lib/libc.a(ioftell.o): In function `ftell': 
(.text+0x1ab): undefined reference to `_Unwind_Resume'
/usr/lib/libc.a(ioftell.o):(.eh_frame+0xde): undefined reference to `__gcc_personality_v0' 
/usr/lib/libc.a(iofwrite.o): In function `fwrite': 
(.text+0x144): undefined reference to `_Unwind_Resume'
/usr/lib/libc.a(iofwrite.o):(.eh_frame+0xde): undefined reference to `__gcc_personality_v0' 
.
.
.

这次出现的错误更多!我们的函数只使用了一个小小的printf,竟引用那么多的未定义函数,此路更不通。

看来只要调用了库函数,恶梦将不断。下面引用《程序员的自我修养》中的例子,不使用printf库函数。

打印字符串使用到write系统调用,退出程序使用到了exit系统调用。这里使用汇编代码仿照该系统调用。

下面是完整的nomain.c代码:

char* str = "hello world!\n";

void myprint(void)
{
/*
* write(int fd, const void *buf, size_t count);
* 系统调用通过int 0x80中断实现
* eax:4,write系统调用号
* ebx:第一个参数,0,指定文件描述符为0(stdout)
* ecx:第二个参数,字符串地址(?)
* edx:第三个参数,字符串长度13
*/
 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 myexit(void)
{
/*
* exit(code)
* eax:1,exit系统调用号
* ebx:退出码(exit code)
*/
 asm( "movl $42, %ebx \n\t"
      "movl $1, %eax \n\t"
      "int $0x80 \n\t");
}

void nomain(void)
{
 myprint();
 myexit();
}

编译测试:

$ gcc -c -fno-builtin main.c (可不需要-fno-builtin选项) 
 $ ld -static -e nomain main.o -o a.out 
 $ ./a.out 
 hello world!
 $ echo $? 
 42

我的本意是想研究一下各个库之间的相互依赖关系,网上有资料说使用ld命令的--start-group和--end-group选项来解决,在U-Boot的Makefile中的确也看到了。不过自己没有顺利找到一个可以测试的例子。限于能力及时间,这个研究暂时搁置了。等以后对linux底层的东西更加了解时再来研究亦不晚。

参考资料:

1、如果想了解关于bin文件及汇编、连接的知识,请用google搜索“Making plain binary files using a C compiler”,作者是Cornelis Frank,写于2000年,年代虽久,经典依旧。

2、《程序员的自我修养--链接、装载与库》,一本需要慢慢研读的好书。

转载于:https://www.cnblogs.com/wangkangluo1/archive/2012/06/28/2566554.html

ld 命令看内存布局 汇编级调试相关推荐

  1. 从内存布局上看,Rust的胖指针到底胖在栈上还是堆上?

    作者 | 马超       责编 | 张红月 出品 | CSDN 博客 2020 年转眼间白驹过隙般飞奔而去,在岁末年初的当口,笔者在回顾这一年程序员世界的大事件后,突然发觉如何避免程序员面向监狱编程 ...

  2. 图文并茂,傻瓜都能看懂的 JVM 内存布局

    本 JVM 系列属于本人学习过程当中总结的一些知识点,目的是想让读者更快地掌握 JVM 相关的知识要点,难免会有所侧重,若想要更加系统更加详细的学习 JVM 知识,还是需要去阅读专业的书籍和文档. 本 ...

  3. C++虚继承(四) --- /d1 reportSingleClassLayout插入看类内存布局

    1 #include <iostream> 2 using namespace std; 3 class base1 4 { 5 int a; 6 double b; 7 char c; ...

  4. vs开发人员命令查看C++类 data member 内存布局

    C++中类的数据成员在内存中时如何分布的,有继承,虚拟继承等情况下又是怎么分布的?在VS编译器中可以查看. 源代码如下: #include<iostream> using namespac ...

  5. 【C++拾遗】 从内存布局看C++虚继承的实现原理

    2019独角兽企业重金招聘Python工程师标准>>> 原创作品,转载请标明:http://blog.csdn.net/xiejingfa/article/details/48028 ...

  6. 看内存溢出的linux命令

    看内存溢出的linux命令 1.jmap -heap pid 看jvm 情况 2.ps -aux | grep "java" 查所有java进程 3.kill -9 18965 杀 ...

  7. Xen的内存布局及其启动

    我会在接下来几篇博客里面介绍Xen的memory.这些都是我在看了各种资料,并且研究了Xen的代码之后的个人总结.之所以写这个系列,是感觉现在网络上没有什么比较具体介绍Xen内存的资料,这里有一个,但 ...

  8. 【逆向工程】C/C++的反汇编表示详解(1)函数调用,栈平衡,变量与参数的内存布局

    很多人学完汇编,去看C/C++的反汇编就会很懵,发现单独看一条指令看的明明白白,但连在多条指令连在一起就不知道有什么作用了,如 push ebp mov ebp,esp sub esp,40h lea ...

  9. linux下的ld命令(1)

    使用ld 本文档介绍GNU连接器ld的2.14版本. 本文档在GNU自由文档许可证下发行.在"GNU自由文档许可证"一章中有关于本许可证的一份拷贝. 概述 'ld'把一定量的目标文 ...

  10. java判断字符串st6_是否包含st5_第 18 章 在机器指令级调试

    第 18 章 在机器指令级调试 本章介绍如何在机器指令级使用事件管理和进程控制命令.如何显示指定地址处的内存内容以及如何显示源代码行及其相应的机器指令.next 命令.step 命令.stop 命令和 ...

最新文章

  1. 《HTML5开发手册》——2.4 初学者“菜谱”:使用address元素提供通信信息
  2. hot编码 字符one_使用字符级RNN生成名字
  3. Windows保护模式学习笔记(十)—— TLB
  4. P2825 [HEOI2016/TJOI2016]游戏
  5. (多线程)leetcode1117. H2O 生成 认识Java中的PV原语
  6. jx8net一定在所有的方方面面都更坚强更勇敢了吧
  7. wordpress-Sakurairo美化主题模板
  8. MongoDB 基本命令
  9. 自定义表单-列表字段的数据源绑定
  10. php7类型约束,类型约束 - PHP 7 中文文档
  11. 离合器膜片弹簧的优化设计matlab,基于matlab目标函数的建立优化离合器膜片弹簧的设计研究.doc...
  12. 服装行业进销存软件有哪些简单好用又便宜的?
  13. GTP 协议常用术语
  14. 减少计算机硬盘,电脑磁盘分区会降低性能?
  15. Halcon根据两条线拟合中线
  16. 三大思维导图软件比较
  17. 频率计的交流耦合和直流耦合的区别_示波器DC/AC耦合设置及影响
  18. 【Java】Unicode转中文代码实现
  19. CSP初赛篇·知识大纲(未完成)
  20. 偏微分方程的matlab解法微盘,偏微分方程的MATLAB数值解法.pdf

热门文章

  1. 师妹问我:如何在7分钟内彻底搞懂word2vec?
  2. Transformer为啥在NER上表现不好
  3. BERT源码分析(二)
  4. 训练加速3倍!字节跳动推出业界首个NLP模型全流程加速引擎
  5. 百面机器学习—6.PCA与LDA要点总结
  6. 机器学习基础算法33-HMM实践
  7. 【Day 1】机器阅读理解——机器阅读理解简介
  8. 运维人必知必会的Zabbix核心命令
  9. 阿里云专家带你揭秘云计算数据底座——对象存储
  10. Spark 和 Hadoop MapReduce 对比