gpt4 book ai didi

gcc - 如何链接到外部 THUMB 代码?

转载 作者:行者123 更新时间:2023-12-04 20:16:43 28 4
gpt4 key购买 nike

我正在为需要链接到现有 THUMB 代码的嵌入式内核 (ARM7TDMI) 编写 THUMB 代码。我正在使用 GNU ARM 嵌入式工具链 ( link )。我无法让链接器将现有的外部代码视为 THUMB;好像一直以为是ARM。我链接到的现有代码绝对是静态的,无法更改/重新编译(基本上,它是位于 ROM 芯片上的普通二进制文件)。

这是一个示例程序,multiply.c ,这说明了这个问题:

extern int externalFunction(int x);
int multiply(int x, int y)
{
return externalFunction(x * y);
}

编译使用:
arm-none-eabi-gcc -o multiply.o -c -O3 multiply.c -march=armv4t -mtune=arm7tdmi -mthumb
arm-none-eabi-ld -o linked.o multiply.o -T symbols.txt

哪里 symbols.txt是一个简单的链接器脚本:
SECTIONS
{
.text 0x8000000 : { *(.text) }
}
externalFunction = 0x8002000;

当我 objdump -d linked.o ,我得到:
08000000 <multiply>:
8000000: b510 push {r4, lr}
8000002: 4348 muls r0, r1
8000004: f000 f804 bl 8000010 <__externalFunction_from_thumb>
8000008: bc10 pop {r4}
800000a: bc02 pop {r1}
800000c: 4708 bx r1
800000e: 46c0 nop ; (mov r8, r8)

08000010 <__externalFunction_from_thumb>:
8000010: 4778 bx pc
8000012: 46c0 nop ; (mov r8, r8)
8000014: ea0007f9 b 8002000 <externalFunction>

它不是直接分支到 0x8002000,而是分支到一个 stub ,该 stub 首先切换到 ARM 模式,然后在 ARM 模式下分支到 0x8002000。我希望 BL 直接分支到 0x8002000 并保持在 THUMB 模式,以便我得到这个:
08000000 <multiply>:
8000000: b510 push {r4, lr}
8000002: 4348 muls r0, r1
8000004: ???? ???? bl 8002000 <__externalFunction>
8000008: bc10 pop {r4}
800000a: bc02 pop {r1}
800000c: 4708 bx r1

撇开 ABI 和调用约定问题不谈,我该如何实现?

最佳答案

一种方法是让它做你想做的事

分支

.thumb
.thumb_func
.globl branchto
branchto:
bx r0

so.c
extern unsigned int externalFunction;
extern int branchto ( unsigned int, int );
int fun ( int x )
{
return(branchto(externalFunction,x)+3);
}


SECTIONS
{
.text 0x8000000 : { *(.text) }
}
externalFunction = 0x8002001;

生产
08000000 <fun>:
8000000: 4b04 ldr r3, [pc, #16] ; (8000014 <fun+0x14>)
8000002: b510 push {r4, lr}
8000004: 0001 movs r1, r0
8000006: 6818 ldr r0, [r3, #0]
8000008: f000 f806 bl 8000018 <branchto>
800000c: 3003 adds r0, #3
800000e: bc10 pop {r4}
8000010: bc02 pop {r1}
8000012: 4708 bx r1
8000014: 08002001 stmdaeq r0, {r0, sp}

08000018 <branchto>:
8000018: 4700 bx r0

罗斯里奇在评论中的解决方案有效
static int (* const externalFunction)(int x) = (int (*)(int)) 0x80002001;
int fun ( int x )
{
return((* externalFunction)(x)+3);
}

但是硬编码的地址在代码中而不是链接器脚本中,如果这很重要,正在尝试解决该问题并且无法解决。
08000000 <fun>:
8000000: b510 push {r4, lr}
8000002: 4b03 ldr r3, [pc, #12] ; (8000010 <fun+0x10>)
8000004: f000 f806 bl 8000014 <fun+0x14>
8000008: 3003 adds r0, #3
800000a: bc10 pop {r4}
800000c: bc02 pop {r1}
800000e: 4708 bx r1
8000010: 80002001 andhi r2, r0, r1
8000014: 4718 bx r3
8000016: 46c0 nop ; (mov r8, r8)

我更喜欢这样的装配解决方案来强制我想要的确切指令。自然地,如果您在外部函数中进行了链接,它就会/应该会起作用(有一些异常(exception),但 gnu 非常擅长在链接器中为您解析 arm/thumb 的来往)。

我实际上并不认为它是 gnu 错误,而是他们需要在链接器脚本中以某种方式将该变量声明为拇指函数地址,而不仅仅是一些通用链接器定义的变量(同样作为 arm 函数地址)。就像 .thumb_func 一样(或更长的函数/过程声明)
.word branchto

.thumb
.globl branchto
branchto:
bx r0

8000018: 0800001c stmdaeq r0, {r2, r3, r4}

0800001c <branchto>:
800001c: 4700 bx r0


.word branchto

.thumb
.thumb_func
.globl branchto
branchto:
bx r0

8000018: 0800001d stmdaeq r0, {r0, r2, r3, r4}

0800001c <branchto>:
800001c: 4700 bx r0

只需阅读 gnu 链接器文档,就有希望得到你想要的
SECTIONS
{
.text0 0x08000000 : { so.o }
.text1 0x08002000 (NOLOAD) : { ex.o }
}

ex.o 来自一个虚拟功能,让每个人都开心
int externalFunction ( int x )
{
return(x);
}

08000000 <fun>:
8000000: b510 push {r4, lr}
8000002: f001 fffd bl 8002000 <externalFunction>
8000006: 3003 adds r0, #3
8000008: bc10 pop {r4}
800000a: bc02 pop {r1}
800000c: 4708 bx r1

并且 NOLOAD 将虚拟函数保留在二进制文件之外。
arm-none-eabi-objcopy so.elf -O srec --srec-forceS3 so.srec

S00A0000736F2E7372656338
S3150800000010B501F0FDFF033010BC02BC0847C0461E
S315080000104743433A2028474E552920362E322E305C
S31508000020004129000000616561626900011F000046
S3150800003000053454000602080109011204140115CA
S31008000040011703180119011A011E021E
S70500000000FA

请注意它并不完美,有额外的垃圾被拉进来,也许是符号
08000000 <fun>:
8000000: b510 push {r4, lr}
8000002: f001 fffd bl 8002000 <externalFunction>
8000006: 3003 adds r0, #3
8000008: bc10 pop {r4}
800000a: bc02 pop {r1}
800000c: 4708 bx r1
800000e: 46c0 nop ; (mov r8, r8)
8000010: 3a434347
8000014: 4e472820
8000018: 36202955
800001c: 302e322e
8000020: 00294100
8000024: 65610000
8000028: 00696261
800002c: 00001f01
8000030: 54340500
8000034: 08020600
8000038: 12010901
800003c: 15011404
8000040: 18031701
8000044: 1a011901

您可以在 srec 中看到,但是 0x08002000 代码不存在,因此您的实际外部函数将被调用。

如果您不想要任何 asm,我会只制作您想要的指令或带有赋值的函数指针。

关于gcc - 如何链接到外部 THUMB 代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43270914/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com