问题描述
9-main.c :
#include <stdio.h>
int mult(int);
int main(){
int result = mult(5);
printf("Result: %d\n",result);
return 0;
}
9 muls.s :
.global mult
mult:
mov r1,r0
lsl r0,r0,#4
add r0,r1,r0
bx lr
我正在尝试链接它们:
$ arm-linux-gnueabihf-gcc 9-main.c 9-mult.s
但是如果我执行a.out:
$ ./a.out
Illegal instruction
可能是什么原因?
解决方法
您确实需要获取手臂文档并学习指令集。
您应该反汇编程序进行确认。第一个问题是您是否在x86上交叉编译,然后尝试在x86上运行ARM?我认为您会遇到其他错误。接下来是a.out文件格式问题,它可能是原始的,因此尝试在aarch64模式下运行aarch32可能是错误的指令或...
对于armv7-64位手臂上的兼容模式(armv8 ...),如果被告知或为此而构建,则gcc编译器将默认为thumb / thumb2模式。
int mult(int);
int fun ( void )
{
return(mult(5)+1);
}
00000000 <fun>:
0: e96d 3e02 strd r3,lr,[sp,#-8]!
4: f04f 0005 mov.w r0,#5
8: f7ff fffe bl 0 <mult>
c: f100 0001 add.w r0,r0,#1
10: bd08 pop {r3,pc}
12: bf00 nop
然后按书面要求
.global mult
mult:
mov r1,r0
lsl r0,#4
add r0,r1,r0
bx lr
除非在命令行中另行指定(否则),否则默认为布防
00000000 <mult>:
0: e1a01000 mov r1,r0
4: e1a00200 lsl r0,#4
8: e0810000 add r0,r0
c: e12fff1e bx lr
因为在gnu链接器的眼中,然后在链接时,mult未被标记为功能标签
00002000 <fun>:
2000: e96d 3e02 strd r3,#-8]!
2004: f04f 0005 mov.w r0,#5
2008: f000 f804 bl 2014 <mult>
200c: f100 0001 add.w r0,#1
2010: bd08 pop {r3,pc}
2012: bf00 nop
00002014 <mult>:
2014: e1a01000 mov r1,r0
2018: e1a00200 lsl r0,#4
201c: e0810000 add r0,r0
2020: e12fff1e bx lr
景气,这是您的错。 bl不使用蹦床就意味着它处于拇指模式,而现在它正尝试执行这些字节,因为拇指指令不起作用。它可能会存活一段时间,但最终会出错。
(Frant已为您确认了这一点,假设这是您处理此特定故障的路径)
所以您有几种选择,可以阅读Frant的答案:
.global mult
.type mult,%function
mult:
mov r1,r0
bx lr
告诉工具多为功能标签,重新组装并重新链接:
00002000 <fun>:
2000: e96d 3e02 strd r3,#5
2008: f000 e804 blx 2014 <mult>
200c: f100 0001 add.w r0,r0
2020: e12fff1e bx lr
因为它是armv7,所以我们得到了blx thumb2扩展名,如果我在整个项目中指定armv4t,那么我们将得到我期望的蹦床。两者都取决于指令集,而armv4t可以在64位处理器的aarch32兼容模式侧工作。
00002000 <fun>:
2000: b510 push {r4,lr}
2002: 2005 movs r0,#5
2004: f000 f80c bl 2020 <__mult_from_thumb>
2008: 3001 adds r0,#1
200a: bc10 pop {r4}
200c: bc02 pop {r1}
200e: 4708 bx r1
00002010 <mult>:
2010: e1a01000 mov r1,r0
2014: e1a00200 lsl r0,#4
2018: e0810000 add r0,r0
201c: e12fff1e bx lr
00002020 <__mult_from_thumb>:
2020: 4778 bx pc
2022: e7fd b.n 2020 <__mult_from_thumb>
2024: eafffff9 b 2010 <mult>
链接器添加mult_from_thumb蹦床以在拇指模式和手臂模式之间转换。 bx lr可以处理模式切换,因此您只需要在进入时就不需要蹦床。
您的另一选择是像拇指一样构建多人
.thumb
.global mult
mult:
mov r1,r0
bx lr
00002000 <fun>:
2000: b510 push {r4,#5
2004: f000 f804 bl 2010 <mult>
2008: 3001 adds r0,#1
200a: bc10 pop {r4}
200c: bc02 pop {r1}
200e: 4708 bx r1
00002010 <mult>:
2010: 1c01 adds r1,#0
2012: 0100 lsls r0,#4
2014: 1808 adds r0,r0
2016: 4770 bx lr
但是如果从布防模式代码中调用,这会出错。
使用gnu汇编程序,您可以使用.type ... function或.thumb_func使其更正确。
.thumb
.global mult
.thumb_func
mult:
mov r1,r0
2016: 4770 bx lr
相同的机器代码,因此.thumb会使它工作起来很傻,但是将标签声明为函数与将其声明为全局一样重要。使用.type,您可以将其放置在.globl所处的任何位置,但.thumb_func必须位于标签之前,而不是立即放置,但基本上是它找到的下一个标签将被标记为函数。
所以之后
arm-linux-gnueabihf-gcc 9-main.c 9-mult.s -o myprog.elf
在学习asm时,有时甚至不是在学习asm时,当然,如果您在混合语言,则应始终遵循以下条件:
arm-linux-gnueabihf-objdump -D myprog.elf
并检查输出。
可以仅对代码使用小写字母-d,大写字母-D还将包括数据部分,这些数据部分通常对于确保已构建所需的内容同样重要。
为完成您的问题,我建议您分解并发布主要功能和多重功能,以查看是否存在互通问题。还是您改为尝试在x86或类似系统上运行arm二进制文件?
如果您检查编译器的完整输出,则Frant显示了一组更详细的指令
.cpu cortex-a72
.eabi_attribute 20,1
.eabi_attribute 21,1
.eabi_attribute 23,3
.eabi_attribute 24,1
.eabi_attribute 25,1
.eabi_attribute 26,1
.eabi_attribute 30,2
.eabi_attribute 34,1
.eabi_attribute 18,4
.file "so.c"
.text
.align 1
.p2align 2,3
.global fun
.arch armv8-a
.arch_extension crc
.syntax unified
.thumb
.thumb_func
.fpu softvfp
.type fun,%function
fun:
@ args = 0,pretend = 0,frame = 0
@ frame_needed = 0,uses_anonymous_args = 0
strd r3,#-8]!
mov r0,#5
bl mult
add r0,#1
pop {r3,pc}
.size fun,.-fun
.ident "GCC: (GNU) 10.2.0"
您将会看到.type函数。他们在这里进行了两次浸渍,并同时执行了.type和.thumb_func,这是有意义的,这是算法驱动的输出。
,您正在为初学者在不平凡的环境中编译/执行:在aarch32
系统上编译/链接/执行aarch64
C /汇编代码的混合。
我建议您开始指定要组装的体系结构以及所使用的确切指令集-这对于想要帮助的人来说是有用的信息-并使用一些标准指令来定义GNU AS汇编中的功能语言,它们将由gcc编译器生成的方式:
.arch armv7-a // target architecture is armv7-a/Aarch32
.fpu vfpv3-d16 // specify available floating-point hardware
.syntax unified // use unified assembler syntax
.arm // generate 32 bit Arm code
.type mult,%function // 'mult' symbol is related to a function
.global mult // 'mult' is a global symbol
.text // code will be put into the .text section
mult:
mov r1,r0
bx lr
.end // end of program
./a.out
Result: 85
有关更多详细信息,请参阅GNU AS documentation。
我仍在寻找问题的根本原因,实际上是通过使用.type mult,%function
来解决的。请注意,在Cortex-A7
Linux系统上确实会发生完全相同的错误,这就是用户使用的是运行64位Linux的事实。
编译两个可执行文件(带有/不带有.type指令)并比较readelf -a
命令的输出仅显示一个区别:
267c267
< 104: 00000534 0 NOTYPE GLOBAL DEFAULT 13 mult
---
> 104: 00000534 0 FUNC GLOBAL DEFAULT 13 mult
更新:
old_timer指出了您的问题的原因-稍后请参见他的评论。
您的编译器默认情况下会生成thumb2 / T32代码,但由于未指定要在哪里使用的指令集,因此默认情况下,汇编代码为arm / A32。使用gcc -marm
选项(arm / A32)编译原始代码可以正常工作:
arm-linux-gnueabihf-gcc-10 -g -marm -o mult mult.c mult.s
./mult
Result: 85
另一种选择是强制GNU AS在mult.s中生成thumb2 / T32代码:
.thumb
.global mult
mult:
mov r1,r0
bx lr
arm-linux-gnueabihf-gcc-10 -g -o mult mult.c mult.s
./mult
Result: 85