|
- 首先贴上源代码。
- #文件名test.s
- .data
- msg: .string "$0</span>-<span class="hljs-variable">$8=%d\n"
- .text
- .global _start
- _start:
- movl $0, %eax
- movl $8, %ebx
- subl %ebx, %eax
- pushl %eax
- lea msg, %eax
- pushl %eax
- call printf
- movl $0, %ebx
- movl $1, %eax
- int $0x80
复制代码 功能非常简单,就是计算eax减去ebx的值,然后调用c语言printf函数输出(参数列表中的参数逆向压
入堆栈,然后“call printf“即可)。
汇编
上面的代码采用的是AT&T语法,所以使用GNU as汇编器。命令如下
as –32 -otest.o test.s
关键是–32选项,它告诉汇编器这是32位的程序。否则,默认生成64位的目标文件。
链接
在Linux系统中许多软件都会使用彼此提供的函数库来完成特殊的功能。Linux中的函数库分为动态函数
库和静态函数库。
静态函数库。这类函数库通常扩展名为libxxx.a。在程序编译的时候会直接被整合到程序中,生成的程
序可以独立执行。程序文件通常比较大,当函数库升级时整个程序需要重新编译才能使用新版本的函
数库。
动态函数库。这类函数库的扩展名为libxxx.so。在程序编译时候,程序中仅会保留指向函数库的Pointer
而已,程序执行时需要函数库时会根据这个Pointer去相应的路径读取。程序文件比较小,函数库升级
不需要重新编译程序就可使用新版的函数库(前提是函数库的名称路径不变)。
上面说了这么多,是因为后面碰到的问题与这个概念相关。先用链接命令尝试一下,当然是会报错的。
[liu@localhost 文档]$ ld -m elf_i386 -otest test.o test.o:在函数‘_start’中:
(.text+0x15):对‘printf’未定义的引用
-m选项是用来生成32位程序的,照着写就好了。因为printf是c语言的库函数,我们这里使用的是动态
链接,所以的链接的时候需要指明函数库。但是,我们的平台是64位的,当然不可能包含32位的函数
库,所以这里要先安装linux系统提供的c语言函数库glibc。这里偷下懒,复制一下百度百科的解释。
glibc是GNU发布的libc库,即c运行库。glibc是linux系统中最底层的api,几乎其它任何运行库都会依赖于
glibc。glibc除了封装linux操作系统所提供的系统服务外,它本身也提供了许多其它一些必要功能服务的
实现。
glibc 的主体,分布 /lib 与 /usr/lib 中,包括 libc 标准 C 函式库、libm 数学函式库、libcrypt加密与编码
函式库、libdb 资料库函式库、libpthread 行程多执行绪函式库、libnss 网路服务函式库 ….等等。这些
都是可分享函式库,档名都以 .so 做结尾。/lib/ld*.so 是程式与函式库连结的工具。有的用于程式编译
时将程式与函式库内的函式物件连结,在只支援静态连结的系统中,此连结方式就是直接将所需的物
件自函式库中抽出来与程式的可执行档相连,而在支援可分享函式库的系统中,在程式编译时期的连
结只是在执行档中纪录了那些函式物件是存在那个函式库档案中,等该程式开始执行时,则由另一个
负责动态连结的ld*.so 将所需的函式库连结好并执行。 一般而言,负责程式编译时期的连结器档名为
ld. so,而负责程式执行时的动态连结器档名为ld- .so 或 ld-linux. so (在 GNU/Linux 系统中)。
搜索可用的glibc软件包。
- [root@localhost ~]# yum search glibc
- 已加载插件:fastestmirror, langpacks
- Loading mirror speeds from cached hostfile
- * base: mirrors.sina.cn
- * extras: mirrors.sina.cn
- * updates: mirrors.cqu.edu.cn
- ================================= N/S matched: glibc =================================
- glibc-common.x86_64 : Common binaries and locale data for glibc
- compat-glibc.x86_64 : Compatibility C library
- compat-glibc-headers.x86_64 : Header files for development using standard C libraries.
- glibc.i686 : The GNU libc libraries
- glibc.x86_64 : The GNU libc libraries
- glibc-devel.i686 : Object files for development using standard C libraries.
- glibc-devel.x86_64 : Object files for development using standard C libraries.
- glibc-headers.x86_64 : Header files for development using standard C libraries.
- glibc-static.i686 : C library static libraries for -static linking.
- glibc-static.x86_64 : C library static libraries for -static linking.
- glibc-utils.x86_64 : Development utilities from GNU C library
- kdesdk-kmtrace.x86_64 : Assist with malloc debugging using glibc's "mtrace"
- : functionality
- kernel-headers.x86_64 : Header files for the Linux kernel for use by glibc
- latrace.i686 : LD_AUDIT feature frontend for glibc 2.4+
- latrace.x86_64 : LD_AUDIT feature frontend for glibc 2.4+
- 名称和简介匹配 only,使用“search all”试试。
- [root@localhost ~]# yum install glibc.i686
- 要安装32位的就选glibc.i686,64位就选glibc.x86_64。这里肯定选前者了。现在重新链接试下
- [root@localhost ~]# ld -m elf_i386 -lc -otest test.o
- ld: skipping incompatible /usr/lib64/libc.so when searching for -lc
- ld: cannot find test.o: 没有那个文件或目录
- [root@localhost ~]#
复制代码 -l选项指定c函数库libc.so,因为动态函数库命名格式libxxx.so,所以只用写xxx就可以了。提示说找到
了一个不兼容的/usr/lib64/libc.so,为什么是在64位目录下找呢?我们用的是64位系统当然要在64位
目录下找了。其实并不是这个逻辑,这和/etc/ld.so.conf配置文件有关。我们可以用-L命令指定搜索
的目录
- [root@localhost 文档]# ld -melf_i386 -lc -L /usr/lib -otest test.o
- [root@localhost 文档]# ./test
- -bash: ./test: 权限不够
复制代码 纳尼,又出现问题了。我一度认为这是权限问题,root账户不应该阿。于是检查用户权限设置和
SELinux,发现没有问题。为了这个程序我花费了两天的时间,实在是耗不起时间,我放弃了。今
天早上来,想试试运气,在这里看到了一篇文章 [原创]Linux环境汇编语言编程初步——使用C库
函数 。试了一下结果成功了。
- [root@localhost 文档]# ld -melf_i386 --dynamic-link /usr/lib/ld-linux.so.2 -lc -L /usr/lib -otest test.o
- [root@localhost 文档]# ./test
- $0</span>-<span class="hljs-variable">$8=-8
- [root@localhost 文档]#
- 文章中的作者解释说,ld-linux.so.2是动态加载器用来查找libc.so的。那默认的动态加载器是什么呢?
- [root@localhost 文档]# ll -Z /usr/lib64 | grep ld-linux
- lrwxrwxrwx. root root system_u:object_r:lib_t:s0 ld-linux-x86-64.so.2 -> ld-2.17.so
- lrwxrwxrwx. root root system_u:object_r:lib_t:s0 ld-lsb-x86-64.so.3 -> ld-linux-x86-64.so.2
- [root@localhost 文档]# ll -Z /usr/lib | grep ld-linux
- lrwxrwxrwx. root root system_u:object_r:lib_t:s0 ld-linux.so.2 -> ld-2.17.so
- [root@localhost 文档]#
复制代码 ld-linux.so.2和ld-linux-x86-64.so.2都是链接文件,都指向ld-2.17.so。但他们指向的是不同的文件,因
为在不同的目录。我猜测默认的加载器应该是ld-linux-x86-64.so.2,可能因为它是64位函数库的加载
器所以无法读取32位函数库的程序。就先这么理解吧,不能把时间都耗在这里,还要继续往前走,不
是吗?
|
|