要解决的问题如下:
/usr/bin/ld: 当搜索用于 /usr/lib/x86_64-linux-gnu//libc.so 时跳过不兼容的 -lc
或者在连接的时候ld提示
ld: i386:x86-64 architecture of input file `multest.o’ is incompatible with i386 output
或者编译生成可执行文件运行后提示
bash: ./multest: 正在访问一个已毁坏的共享库。
我的系统是64位的ubuntu20.04。
汇编代码例子如下(已将入口点_start标签改为main)
# multest.s - An example of using the MUL instruction
.section .data
data1:
.int 315814
data2:
.int 165432
result:
.quad 0
output:
.asciz "The result is %qd\n"
.section .text
.globl main
main:
nop
movl data1, %eax
mull data2
movl %eax, result
movl %edx, result+4
pushl %edx
pushl %eax
pushl $output
call printf
add $12, %esp
pushl $0
call exit
方式一:gcc编译汇编语言程序
- 使用gcc汇编程序时有一个问题,GNU连接器查找_start标签以便确定程序的开始位置,但是gcc查找的是main标签,所以
必须把汇编程序中的_start标签改为main
,如上面的程序示例所示。 - 首先确保安装了
libc6-dev-i386
和lib32z1(ia32-libs已被lib32z1取代); - 然后就可以输入gcc命令成功编译连接成elf32可执行程序了:
gcc -m32 -o multest multest.s
- 把output中的格式字符串改为十六进制格式:
output:
.asciz "The result is 0x%qx\n"
方式二:as编译汇编语言程序
说是push操作无效,原因是 64 位系统和 32 位系统的差别引起的。
解决方法一
如果不修改源代码添加.code32指令的话,也不修改源代码为64位的汇编,要解决这个问题,就需要命令64位系统按照32位的去汇编,as参数是–32, ld参数是-m elf_i386,即:
as --32 -o multest.o multest.s
我们可以看到,此时生存的.o目标文件是elf 32位的。
然后连接成可执行文件:
ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o multest -L /usr/lib32/ -lc multest.o
- 这里重点要说明一下我的标准C库函数所在的位置:
-m elf_i386:表示按照elf_i386的模块进行连接,即32位的。
-dynamic-linker /lib/ld-linux.so.2:用于运行时动态加载libc.so动态库的。否则执行生成的可执行文件时会出错。
-lc: 因为程序中调用了标准的C库函数printf和exit,因此需要连接C动态库libc.so,所以需要参数-lc来指定连接的库文件,一般而言libxxx.so采用-lxxx的参数。
-L/lib:我的系统有多个libc.so,包括64位的,32位的,arm结构的,如下图所示,能搜出很多个libc.so。
而/usr/lib32/libc.so
才是32位x86系统所需要的动态库,所以使用-L /usr/lib32
来指定库文件的路径,那么-L /usr/lib32 –lc
就指定了连接的是/usr/lib32/libc.so。
- 他的libc.so都不兼容:
尝试的解决方法二(未解决)
在代码开头添加 .code32 即可:
- 当汇编语言程序被转换为可执行文件时,连接器必须知道指令码中的起始点是什么,GNU汇编器声明了一个默认标签_start作为应用程序的入口点,所以修改汇编程序中的main标签为_start标签:
我们可以看到,此时生存的.o目标文件是elf 64位的,这就会导致ld连接的时候出问题。
- 因为.o目标文件是elf 64位的,所以我们链接的时候可以试试生存64位可执行文件的选项:
- 把加载动态库的程序,以及标准的C库函数也改为64位的试试:
仍然出错。。。只能待以后解决。。。
参考链接:
https://www.cnblogs.com/kenzhang1031/p/3411044.html
https://blog.csdn.net/q3733353520/article/details/38332465
https://blog.csdn.net/Asdfffy/article/details/88055350
http://cn.voidcc.com/question/p-yxssrsce-bgg.html
https://blog.csdn.net/weixin_39989159/article/details/116676721
GCC 64位程序的makefile条件编译心得——32位版与64位版、debug版与release版(兼容MinGW、TDM-GCC)
https://www.cnblogs.com/zyl910/archive/2012/08/14/gcc64_make.html
备注:
fatal error: iostream.h: No such file or directory
#include<iostream.h> 非标准输入输出流, 这个写法是以前C语言的写法,上个世纪八九十年代的书中一般采用这种写法,现在已经不适用了。
iostream.h时代没有名词空间,即所有库函数包括头文件iostream.h都声明在全局域。为了体现结构层次, 避免名字定义冲突, c++标准委员会 特别引入了“名字空间的定义”,即namespace。 引入了名词空间这一概念,并把所有库函数声明由全局域改到了名词空间std。
所以,新的标准是:
#include // 标准输入输出流
using namespace std;
(因为iostream声明在std中,故而要加上这句,除非你不用库函数,否则错误); 很多编译器都同时支持这两种头文件形式,更好的当然是标准头文件。至于为什么不废除非标准头文件,大概是为了兼容以前的代码吧。 还有一点在标准c++中,所有库函数都没有.h后缀了,如果是c语言的库函数,则去掉后缀,并在开头加上一个c(如,c++的string.h变为string,c语言的stdio.h,变为cstdio,c语言的string.h变为cstring等等)。
ubuntu上gcc加了参数-m32之后报:
fatal error: bits/c++config.h: 没有那个文件或目录”
编译32bit的程序,结果编译的时候,出现了题中的错误。
那是系统还没有安装多版本编译模式的缘故,安装如下插件即可。
sudo apt-get install gcc-multilib g+±multilib
安装这两个就可以支持-m32了.
如果上面的安装最新版失败了,也可以尝试下面的版本。
sudo apt-get install gcc-4.8-multilib g+±4.8-multilib