使用printf

代码

#cpuid2.s -- Using C labrary calls
.section .data
output:
.asciz "The processor Vender is '%s'\n"
.section .bss
.lcomm buffer, 12
.section .text
.globl _start
_start:
movl $0, %eax
cpuid
movl $buffer, %edi
movl %ebx, (%edi)   //含义同cpuid.s,向%edi所指向的buffer内存
movl %edx, 4(%edi)  //位置写入3个寄存器的内容,这3个寄存器存储了
movl %ecx, 8(%edi)  //CPU厂商信息的字符串(12字节)
pushl $buffer       //将buffer和output入栈,为printf提供参数
pushl $output
call printf         //调用C的printf函数
addl $8, %esp       //将堆栈指针回滚8个字节,达到清除printf参数的目的
pushl $0
call exit

.asciz是在定义字符串的时侯在字符串结尾加上空字符(即C语言的\0),这样做的目的是为了让printf能读懂字符串。

.lcomm是在本地内存区域中声明固定长度的未初始化数据,这里初始化了12个字节的空间。

程序里buffer和output内存位置的内容是要向printf传递的参数值:

一个是"The processor Vender is '%s'\n"字符串;

另外一个是由cpuid返回结果(在ebx,edx,ecx三个寄存器中)填充的buffer。

需要通过堆栈来传递参数,所以在程序中使用

pushl $buffer

pushl $output

将参数入栈,printf获取参数是自右向左,即先buffer后output,所以要把buffer后入栈。

参数入栈之后,用call指令调用printf。

exit的情况同上,使用了一个参数--常数0。

汇编

#as -o cpuid2.o cpuid2.s

采用了动态连接的方式,所以C函数没有包含在可执行程序中,需要由另外的程序在运行时加载,ld不知道这个程序在哪里,所以我们还得手动指定

动态链接

#ld -dynamic-linker /lib/ld-linux.so.2 -lc -o cpuid2 cpuid2.o

#./cpuid2

输出

The processor Vendor ID is 'GenuineIntel'

GDB调试

# gdb cpuid2
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-56.el6)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /usr/zhms/AS/chap04/cpuid2...done.
(gdb) break _start
Breakpoint 1 at 0x80481b8: file cpuid2.s, line 10.
(gdb) r
Starting program: /usr/zhms/AS/chap04/cpuid2
Breakpoint 1, _start () at cpuid2.s:10
10          movl $0, %eax
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.80.el6_3.6.i686
(gdb) i r
eax            0x0      0
ecx            0x0      0
edx            0x758470 7701616
ebx            0x767fc4 7765956
esp            0xbffff6c0       0xbffff6c0
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80481b8        134513080
eip            0x80481b8        0x80481b8 <_start>
eflags         0x286    [ PF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
11          cpuid
(gdb) i r
eax            0x0      0
ecx            0x0      0
edx            0x758470 7701616
ebx            0x767fc4 7765956
esp            0xbffff6c0       0xbffff6c0
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80481b8        134513080
eip            0x80481bd        0x80481bd <_start+5>
eflags         0x286    [ PF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
13          movl %ebx, (%edi)
(gdb) i r
eax            0x5      5
ecx            0x6c65746e       1818588270
edx            0x49656e69       1231384169
ebx            0x756e6547       1970169159
esp            0xbffff6c0       0xbffff6c0
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x80481c4        0x80481c4 <_start+12>
eflags         0x286    [ PF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
14          movl %edx, 4(%edi)
(gdb) i r
eax            0x5      5
ecx            0x6c65746e       1818588270
edx            0x49656e69       1231384169
ebx            0x756e6547       1970169159
esp            0xbffff6c0       0xbffff6c0
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x80481c6        0x80481c6 <_start+14>
eflags         0x286    [ PF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
15          movl %ecx, 8(%edi)
(gdb) i r
eax            0x5      5
ecx            0x6c65746e       1818588270
edx            0x49656e69       1231384169
ebx            0x756e6547       1970169159
esp            0xbffff6c0       0xbffff6c0
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x80481c9        0x80481c9 <_start+17>
eflags         0x286    [ PF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
16          pushl $buffer
(gdb) i r
eax            0x5      5
ecx            0x6c65746e       1818588270
edx            0x49656e69       1231384169
ebx            0x756e6547       1970169159
esp            0xbffff6c0       0xbffff6c0
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x80481cc        0x80481cc <_start+20>
eflags         0x286    [ PF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
17          pushl $output
(gdb) i r
eax            0x5      5
ecx            0x6c65746e       1818588270
edx            0x49656e69       1231384169
ebx            0x756e6547       1970169159
esp            0xbffff6bc       0xbffff6bc
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x80481d1        0x80481d1 <_start+25>
eflags         0x286    [ PF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
18          call printf
(gdb) i r
eax            0x5      5
ecx            0x6c65746e       1818588270
edx            0x49656e69       1231384169
ebx            0x756e6547       1970169159
esp            0xbffff6b8       0xbffff6b8
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x80481d6        0x80481d6 <_start+30>
eflags         0x286    [ PF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
0x007b63e0 in printf () from /lib/libc.so.6
(gdb) i r
eax            0x5      5
ecx            0x6c65746e       1818588270
edx            0x49656e69       1231384169
ebx            0x756e6547       1970169159
esp            0xbffff6b4       0xbffff6b4
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x7b63e0 0x7b63e0 <printf>
eflags         0x246    [ PF ZF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
Single stepping until exit from function printf,
which has no line number information.
The processor Vendor ID is 'GenuineIntel'
_start () at cpuid2.s:19
19          addl $8, %esp
(gdb) i r
eax            0x2a     42
ecx            0xbffff6a0       -1073744224
edx            0x8fe364 9429860
ebx            0x756e6547       1970169159
esp            0xbffff6b8       0xbffff6b8
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x80481db        0x80481db <_start+35>
eflags         0x286    [ PF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
20          pushl $0
(gdb) i r
eax            0x2a     42
ecx            0xbffff6a0       -1073744224
edx            0x8fe364 9429860
ebx            0x756e6547       1970169159
esp            0xbffff6c0       0xbffff6c0
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x80481de        0x80481de <_start+38>
eflags         0x296    [ PF AF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
21          call exit
(gdb) i r
eax            0x2a     42
ecx            0xbffff6a0       -1073744224
edx            0x8fe364 9429860
ebx            0x756e6547       1970169159
esp            0xbffff6bc       0xbffff6bc
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x80481e0        0x80481e0 <_start+40>
eflags         0x296    [ PF AF SF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
0x00799060 in exit () from /lib/libc.so.6
(gdb) i r
eax            0x2a     42
ecx            0xbffff6a0       -1073744224
edx            0x8fe364 9429860
ebx            0x756e6547       1970169159
esp            0xbffff6b8       0xbffff6b8
ebp            0x0      0x0
esi            0xbffff6cc       -1073744180
edi            0x80492c0        134517440
eip            0x799060 0x799060 <exit>
eflags         0x246    [ PF ZF IF ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51
(gdb) s
Single stepping until exit from function exit,
which has no line number information.
Program exited normally.
(gdb) i r
The program has no registers now.
(gdb) 

ld-linux.so查找共享库的顺序

这里引出一个问题,怎么知道ld-linux.so.2是什么以及定位

Glibc安装的库中有一个为ld-linux.so.X,其中X为一个数字,在不同的平台上名字也会不同。可以用ldd查看:

#ldd /bin/cat

最后一个没有=>的就是。其中第一个不是实际的库文件,你是找不到的,它是一个虚拟库文件用于和kernel交互。
ld-linux.so是专门负责寻找库文件的库。以cat为例,cat首先告诉ld-linux.so它需要libc.so.6这个库文件,ld-linux.so将按一定顺序找到libc.so.6库再给cat调用。
那ld-linux.so又是怎么找到的呢?其实不用找,ld-linux.so的位置是写死在程序中的,gcc在编译程序时就写死在里面了。Gcc写到程序中ld-linux.so的位置是可以改变的,通过修改gcc的spec文件。

运行时,ld-linux.so查找共享库的顺序
(1)ld-linux.so.6在可执行的目标文件中被指定,可用readelf命令查看
(2)ld-linux.so.6缺省在/usr/lib和lib中搜索;当glibc安装到/usr/local下时,它查找/usr/local/lib
(3)LD_LIBRARY_PATH环境变量中所设定的路径
(4)/etc/ld.so.conf(或/usr/local/etc/ld.so.conf)中所指定的路径,由ldconfig生成二进制的ld.so.cache中

编译时,ld-linux.so查找共享库的顺序
(1)ld-linux.so.6由gcc的spec文件中所设定
(2)gcc --print-search-dirs所打印出的路径,主要是libgcc_s.so等库。可以通过GCC_EXEC_PREFIX来设定
(3)LIBRARY_PATH环境变量中所设定的路径,或编译的命令行中指定的-L/usr/local/lib
(4)binutils中的ld所设定的缺省搜索路径顺序,编译binutils时指定。(可以通过“ld --verbose | grep SEARCH”来查看)
(5)二进制程序的搜索路径顺序为PATH环境变量中所设定。一般/usr/local/bin高于/usr/bin
(6)编译时的头文件的搜索路径顺序,与library的查找顺序类似。一般/usr/local/include高于/usr/include

用 Linux 进行动态链接

ELF映像

Linux 中的动态链接的共享库的过程。当用户启动一个应用程序时,它们正在调用一个可执行和链接格式(Executable and Linking Format,ELF)映像。内核首先将 ELF 映像加载到用户空间虚拟内存中。然后内核会注意到一个称为 .interp 的 ELF 部分,它指明了将要被使用的动态链接器(例如:/lib/ld-linux.so)。

一个ELF头在文件的开始,保存了路线图(road map),描述了该文件的组织情况。sections保存着object 文件的信息,从连接角度看:包括指令,数据,符号表,重定位信息等等。

使用 readelf 来显示程序标题

#readelf -l cpuid2

注意,ld-linux.so 本身就是一个 ELF 共享库,但它是静态编译的并且不具备共享库依赖项。当需要动态链接时,内核会引导动态链接(ELF 解释器),该链接首先会初始化自身,然后加载指定的共享对象(已加载则不必)。接着它会执行必要的再定位,包括目标共享对象所使用的共享对象。

#readelf -l cpuid2.o

There are no program headers in this file.

ldd命令

Linux 提供了很多种查看和解析 ELF 对象(包括共享库)的工具。其中最有用的一个当属 ldd命令,可以使用它来发现共享库依赖项。

#ldd cpuid2

ldd所告诉您的是:该 ELF 映像依赖于 linux-gate.so(一个特殊的共享对象,它处理系统调用,它在文件系统中无关联文件),GNU C库(libc.so)以及 Linux 动态加载器(因为它里面有共享库依赖项)。

#ldd cpuid2.o

ldd: 警告: 你没有执行权限 `./cpuid2.o'
不是动态可执行文件

readelf识别对象内可再定位的C库

readelf 命令是一个有很多特性的实用程序,它让您能够解析和读取 ELF 对象。readelf 有一个有趣的用途,就是用来识别对象内可再定位的项。对于我们这个简单的程序来说,可以看到需要再定位的符号

#readelf -r cpuid2

从这个列表中,您可以看到各种各样的需要再定位(到 libc.so)的 C库调用。

#readelf -r cpuid2.o

readelf查看共享库的依赖库(NEEDED)和搜索名(SONAME)

#readelf -d cpuid2

#readelf -d cpuid2.o

无输出

readelf查看ELF头信息

#readelf -h cpuid2

#readelf -h cpuid2.o

附录

#man readelf

objdump

objdump是用查看目标文件或者可执行的目标文件的构成的GCC工具

反汇编

#objdump -d cpuid2

对于其中的反汇编代码

左边是机器指令的字节,右边是反汇编结果。显然,所有的符号都被替换成地址了, 注意没有加$的数表示内存地址,而不表示立即数。

objdump -x obj 以某种分类信息的形式把目标文件的数据组织(被分为几大块)输出 <可查到该文件的所有动态库>
objdump -t obj 输出目标文件的符号表()
objdump -h obj 输出目标文件的所有段概括()
objdump -j .text/.data -S obj 输出指定段的信息,大概就是反汇编源代码把
objdump -S obj C语言与汇编语言同时显示

更多参考

#man objdump

参考:Linux 动态库剖析

http://www.ibm.com/developerworks/cn/linux/l-dynamic-libraries/

汇编语言使用C库函数和Linux动态链接相关推荐

  1. linux got分析,聊聊Linux动态链接中的PLT和GOT(3)——公共GOT表项

    前文(聊聊Linux动态链接中的PLT和GOT(2)--延迟重定位)提到所有动态库函数的plt指令最终都跳进公共plt执行,那么公共plt指令里面的地址是什么鬼? 把test可执行文的共公plt贴出来 ...

  2. 一篇长文带你深析Linux动态链接的全过程

    目录 为什么要动态链接? 地址无关代码 共享模块的全局变量问题 延迟绑定(PLT) 动态链接相关结构 .interp段 .dynamic段 动态符号表 动态链接重定位表 动态链接时进程堆栈初始化信息 ...

  3. 聊聊Linux动态链接中的PLT和GOT(3)——公共GOT表项

    前文(聊聊Linux动态链接中的PLT和GOT(2)--延迟重定位)提到所有动态库函数的plt指令最终都跳进公共plt执行,那么公共plt指令里面的地址是什么鬼? 把test可执行文的共公plt贴出来 ...

  4. Linux 动态链接和静态链接简析(库名与库文件名)

    原文请见 Linux动态链接和静态链接简析 0. 库名与真正的库文件名 就拿数学库来说,他的库名是 m,他的库文件名是libm.so,很容易看出,把库文件名的头 lib 和尾.so去掉就是库名.(gc ...

  5. 聊聊Linux动态链接中的PLT和GOT(1)——何谓PLT与GOT

    在介绍PLT和GOT出场之前,先以一个简单的例子引入两个主角,各位请看以下代码: #include <stdio.h>void print_banner() {printf("W ...

  6. Linux 动态库剖析

    进程与 API 动态链接的共享库是 GNU/Linux® 的一个重要方面.该种库允许可执行文件在运行时动态访问外部函数,从而(通过在需要时才会引入函数的方式)减少它们对内存的总体占用.本文研究了创建和 ...

  7. 《程序员的自我修养-Ch7_动态链接》

    Ch7 动态链接 7.1 为什么要动态链接 1 静态链接的缺点 1.1 内存和磁盘空间占用 **每个程序都将包含的库函数直接打包使用,使得占用内存和磁盘大.**如下图1所示,其中Program1和Pr ...

  8. 程序员自我修养阅读笔记——动态链接

    1 为什么需要动态链接   动态链接,顾名思义,就是只有在程序需要调用对应的库中的实现时才将对应的库的映像文件加载到内存.相比而言,静态链接是在编译阶段就将需要的目标文件中的相关实现连接到可执行文件中 ...

  9. 程序员的自我修养--链接、装载与库笔记:动态链接

    1. 为什么要动态链接 静态链接诸多缺点,比如浪费内存和磁盘空间.模块更新困难等. 内存和磁盘空间:静态链接的方式对于计算机内存和磁盘的空间浪费非常严重,特别是在多进程操作系统情况下. 程序开发和发布 ...

最新文章

  1. 笔记-项目质量管理-精简
  2. 如何兼容自训练与预训练:更高效的半监督文本分类模型
  3. 静态代理,cglib动态代理,jdk动态代理区别以及流程详解
  4. 郑大远程计算机应用基础第09,郑大远程教育《计算机应用基础》第09章在线测试...
  5. java学习是网上java学习视频好,还是报班比较好
  6. 值得收藏!深度报告解读NB-IoT
  7. 形式语言与自动机 第三章 课后题答案
  8. 痛苦的刷路由器 破校园网 小米mini潘多拉
  9. 程序员来聊一聊信用卡(二)——对信用卡的一些基本认识
  10. 迅雷android 电视,【迅雷电视助手】迅雷电视助手安卓版(Android)2.0下载_太平洋下载中心...
  11. MySQL不等于判断时,null空值处理问题
  12. 01. Web漏洞靶场的搭建
  13. 【华为云技术分享】一文看懂什么是汽车OTA
  14. A. chino with string(ac自动机+floyd矩阵快速幂)
  15. Wex5调用百度地图进行范围签到
  16. 阿里云政企安全加速解决方案的技术架构与应用实践
  17. 萌新如何用板绘画好原画?怎么选择数位板?零基础板绘入门干货篇
  18. kudu table
  19. 计算机毕业设计JAVA汽车租赁系统mybatis+源码+调试部署+系统+数据库+lw
  20. 独立思考:我对google glass的不同看法

热门文章

  1. 【camera】5.相机内嵌图像处理(ISP)介绍
  2. E:By Elevator or Stairs? CF595 DP最短路
  3. 【python】一个目录里面多个python程序文件,统计一下里面有多少行代码。即分别列出:代码、空行、注释的行数。
  4. LeetCode刷题记录13——705. Design HashSet(easy)
  5. grpc 传递上下文_grpc 源码笔记 02:ClientConn
  6. 设置VSCode刷新资源管理器快捷键Ctrl+Shift+R
  7. Linux下正确使用getifaddrs()函数避免内存泄露
  8. coreseek最大检索数只有1000的问题!
  9. Blender赛车动画制作学习教程 Learn Race Car Animation with Blender
  10. 跟着Rocskdb 学 存储引擎:读写链路的代码极致优化