尝试将.c文件与.s文件链接,但出现“非法指令”

问题描述

我有两个文件9-main.c和9-mult.s。

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

有关thumb2 / T32,arm / A32和互连代码的更多详细信息,请参见herehere