64位ubuntu20.04上编译32位汇编程序,并连接C库函数

要解决的问题如下:

/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

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值