为什么 'ld' 在链接没有“-mthumb”的“-mthumb-only”目标文件时不发出警告?

Why doesn't 'ld' warn when linking '-mthumb-only' object files without '-mthumb'?

在我使用 gcc-arm-none-eabi 4.8binutils 2.26 的设置中,当使用 -mthumb 单独编译目标文件时,我得到了相当不确定的行为,但在最后的链接步骤中使用 ld 而没有从链接器得到任何警告。为什么会这样?

未定义的行为可能是(根据我首先询问的非常有帮助的 FOSS 开发人员的说法)由于缺少标志而链接器选择的默认 multilib 体系结构。但是,为什么链接器不警告这个问题?难道它不能很容易地从对象和库文件中检测到链接函数的 ISA 以确定发生了什么可疑的事情吗?

compiling the object files separately with -mthumb but leaving that flag out in the final linking step using ld without getting any warning from the linker. Why is that the case?

除了微控制器配置文件 (Cortex-M) 之外,生成的可执行文件应该可以在大多数 ARM 平台上正常运行。甚至还有一个很好的理由将拇指代码与 ARM 库混合使用:代码大小。

理想情况下是的,它应该从被 linked 的对象中知道。拆解考察不同对象的函数交互

我最近试图证明 gnu tools/linker 在添加蹦床方面有多好。当它一直惨败时。它会把蹦床放在一个方向而不是另一个方向(拇指 to/from 手臂)。我认为这是一个程序集 to/from C 问题,我没有像编译器那样使用过多的指令,所以可能就是这样。

设置一些测试用例非常简单,用为 arm 构建的函数创建一个对象,用为 thumb 构建的函数创建另一个对象,让它们相互调用。在它周围放置足够的结构以使工具 link 没有错误,然后拆卸并检查。

armstart.s

.global _start
_start:
    bl notmain
    b hang
hang:   b .

notmain.c

extern unsigned int one ( unsigned int );
int notmain ( void )
{
    one(1);
    return(0);
}

one.c

extern unsigned int two ( unsigned int x );
unsigned int one ( unsigned int x )
{
    return(two(x+5));
}

two.c

extern unsigned int one ( unsigned int x );
unsigned int two ( unsigned int x )
{
    return(one(x+7));
}

生成文件

ARMGNU = arm-none-eabi
#ARMGNU = arm-linux-gnueabi

AOPS = --warn --fatal-warnings
COPS = -Wall -O2 -nostdlib -nostartfiles -ffreestanding

all : notmain.bin


clean:
    rm -f *.bin
    rm -f *.o
    rm -f *.elf
    rm -f *.list
    rm -f *.bc
    rm -f *.opt.s
    rm -f *.norm.s
    rm -f *.hex

armstart.o : armstart.s
    $(ARMGNU)-as $(AOPS) armstart.s -o armstart.o

notmain.o : notmain.c
    $(ARMGNU)-gcc $(COPS) -c notmain.c -o notmain.o

two.o : two.c
    $(ARMGNU)-gcc $(COPS) -mthumb -c two.c -o two.o

one.o : one.c
    $(ARMGNU)-gcc $(COPS) -c one.c -o one.o

notmain.bin : memmap armstart.o notmain.o one.o two.o
    $(ARMGNU)-ld -o notmain.elf -T memmap armstart.o notmain.o one.o two.o
    $(ARMGNU)-objdump -D notmain.elf > notmain.list
    $(ARMGNU)-objcopy notmain.elf notmain.hex -O ihex
    $(ARMGNU)-objcopy notmain.elf notmain.bin -O binary

部分反汇编:

20000024 <one>:
20000024:   e92d4010    push    {r4, lr}
20000028:   e2800005    add r0, r0, #5
2000002c:   eb000007    bl  20000050 <__two_from_arm>
20000030:   e8bd4010    pop {r4, lr}
20000034:   e12fff1e    bx  lr

20000038 <two>:
20000038:   b510        push    {r4, lr}
2000003a:   3007        adds    r0, #7
2000003c:   f000 f804   bl  20000048 <__one_from_thumb>
20000040:   bc10        pop {r4}
20000042:   bc02        pop {r1}
20000044:   4708        bx  r1
20000046:   46c0        nop         ; (mov r8, r8)

20000048 <__one_from_thumb>:
20000048:   4778        bx  pc
2000004a:   46c0        nop         ; (mov r8, r8)
2000004c:   eafffff4    b   20000024 <one>

20000050 <__two_from_arm>:
20000050:   e59fc000    ldr ip, [pc]    ; 20000058 <__two_from_arm+0x8>
20000054:   e12fff1c    bx  ip
20000058:   20000039    andcs   r0, r0, r9, lsr r0
2000005c:   00000000    andeq   r0, r0, r0

本例中的工具链

arm-none-eabi-gcc (GCC) 6.1.0
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

(binutils 2.26.20160125)

工作得很好。

对于 gcc 5.4.0 和 binutils 2.26.1 也是如此。

查看我们看到的两个对象的 readelf 之间的差异,例如:

< 00000004  00000a1d R_ARM_JUMP24      00000000   two
---
> 00000004  00000a0a R_ARM_THM_CALL    00000000   one