从 C、GCC(裸机)调用 ARM 汇编

发布于 2024-12-28 07:11:59 字数 360 浏览 3 评论 0原文

我正在尝试使用 GCC 在 ARM 中进行一些裸机编程并在 QEMU 上进行测试。每当我从 C 调用 ARM 标签时,我的程序就会挂起。我有一个简单的代码示例,显示了问题 https://gist.github.com/1654392 -- 当我在该代码中调用 activate() 时,它挂起。

我通过 objdump 观察到,当我执行从汇编到 C 代码(从 _start 开始)的 bl 操作时,它会生成一个切换到拇指指令的小包装器。看起来 C 代码都是在拇指指令中生成的,但我所有的汇编都是在 ARM(32 位)指令中生成的。我不明白这是为什么或如何解决它。

I am trying to do some bare-metal programming in ARM with GCC and testing on QEMU. Whenever I call into an ARM label from C, my program hangs. I have a simple example of code that shows the problem at https://gist.github.com/1654392 -- when I call activate() in that code, it hangs.

I have observed with objdump that when I do a bl from assembly to C code (as from _start) it is generating a small wrapper that switches to thumb instructions. It seems that the C code is all being generated in thumb instructions, but all my assembly is being generated in ARM (32-bit) instructions. I cannot figure out why this is or how to fix it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

肤浅与狂妄 2025-01-04 07:11:59

为了从 C 中定义的 THUMB 模式函数调用汇编中定义的 ARM 模式函数,您需要在汇编中将符号定义为函数,并且工具 (Linaro gcc) 将生成一个 blx指令而不是bl

例子:

@ Here, we suppose that this part of code is inside of .code 32

.type fn, %function

fn:
   mov  pc, lr

In order to call an ARM mode function defined in assembly from a THUMB mode function defined in C, you need to define a symbol in assembly as a function, and the tools (Linaro gcc) will produce a blx instruction instead of bl.

Example:

@ Here, we suppose that this part of code is inside of .code 32

.type fn, %function

fn:
   mov  pc, lr
烟酒忠诚 2025-01-04 07:11:59

请参阅 http://github.com/dwelch67/yagbat qemu 目录。

以下是从arm调用arm或thumb的几个示例

start_vector:
    mov sp,#0x20000
    ;@ call an arm function from arm
    bl notmain

    ;@ call a thumb function frm arm
    ldr r0,=0xAABBAABB
    bl hexstring_trampoline

    ;@ call a thumb function frm arm
    ldr r0,=0x12341234
    ldr r1,hexstring_addr
    mov lr,pc
    bx r1

    ;@ call a thumb function frm arm
    ldr r0,=0x12312344
    bl hexstring_trampoline

hang:
    b hang

hexstring_trampoline:
    ldr r1,hexstring_addr
    bx r1

hexstring_addr: .word hexstring

如果您查看指令集参考,您会发现需要使用BX或BLX在arm和thumb状态之间切换。 BLX 不像 BX 那样得到广泛支持。

从定义的角度来看,程序计数器 pc 是一条指令执行期间前面的两条指令。对于thumb 来说是4 个字节,对于arm 来说是8 个字节。无论哪种情况,都有两个指令。要模拟不能用于更改状态的 bl,您需要将返回地址加载到链接寄存器,并使用 bx 根据地址的 lsbit 分支到更改状态的函数。所以

mov lr,pc
bx r1
here:

上面的mov lr,pc加载了这里的地址:这是我们的返回地址,bx r1以状态无关的方式调用该函数。 lr地址的lsbit表示返回的模式,需要始终使用bx返回

pre_thumb:
ldr pc,lr

thumb_capable:
bx lr

编译器分配一条bl指令用于调用函数,链接器稍后填写其余部分,如果太远则需要链接器自行添加的蹦床函数。同样,如果您需要更改模式,bl 会调用一个 Trampoline 函数来执行此操作。我在上面的其中一个模型中模拟了这一点,你可以看到它有点浪费,希望我对编译器只为 bl 分配空间的解释使这一点更清楚,浪费就是总是计划模式更改并且必须为代码中的大多数函数调用插入 nops。

该代码还包括在汇编器中从拇指对arm的调用:

.thumb

.thumb_func
.globl XPUT32
XPUT32:
    push {lr}
    ;@ call an arm function from thumb asm
    ldr r2,=PUT32
    mov lr,pc
    bx r2
    pop {r2}
    bx r2

基本上相同,除了你不能在拇指模式下弹出到lr,你可以弹出到pc,但我不认为切换模式,所以你不能使用它,你再次需要一个备用寄存器。当然,您需要了解调用约定才能知道可以使用哪些寄存器,或者您可以包装另一组推送和弹出来保留除 lr

    push {r2,lr}
    ;@ call an arm function from thumb asm
    ldr r2,=PUT32
    mov lr,pc
    bx r2
    pop {r2}
    mov lr,r2
    pop {r2}
    bx lr

Thumb to拇指或手臂到手臂之外的所有寄存器,如果您可以到达,您只需使用 bl 。 ldr pc,地址如果不能的话。

see http://github.com/dwelch67/yagbat qemu directory.

Here are a couple of examples of calling arm or thumb from arm

start_vector:
    mov sp,#0x20000
    ;@ call an arm function from arm
    bl notmain

    ;@ call a thumb function frm arm
    ldr r0,=0xAABBAABB
    bl hexstring_trampoline

    ;@ call a thumb function frm arm
    ldr r0,=0x12341234
    ldr r1,hexstring_addr
    mov lr,pc
    bx r1

    ;@ call a thumb function frm arm
    ldr r0,=0x12312344
    bl hexstring_trampoline

hang:
    b hang

hexstring_trampoline:
    ldr r1,hexstring_addr
    bx r1

hexstring_addr: .word hexstring

If you look at the instruction set reference you will see that you need to use BX or BLX to switch between arm and thumb states. BLX is not as widely supported as BX.

From a definition standpoint the program counter, pc is two instructions ahead during execution of an instruction. for thumb that is 4 bytes, for arm 8 bytes. Either case two instructions. To simulate a bl which cant be used to change state, you need to load the link register with the return address, and use a bx to branch to the function changing state depending on the lsbit of the address. so the

mov lr,pc
bx r1
here:

the mov lr,pc above loads the address of here: which is our return address, bx r1 in a state independent manner calls the function. the lsbit of the lr address indicates the mode to return to and you need to always use bx to return

pre_thumb:
ldr pc,lr

thumb_capable:
bx lr

The compiler allocates a bl instruction for calling functions, the linker fills in the rest later, if it is too far of a reach then it needs a trampoline function which the linker is adding itself. Likewise if you need to change modes the bl calls a trampoline function that does that. I have modeled that in one of the above to mimic that, you can see it is a bit wasteful, hopefully my explanation of the compiler only allocating space for a bl makes that more clear, wasteful would be to always plan for a mode change and have to insert nops for the majority of the function calls in code.

The code also includes a call to arm from thumb in assembler:

.thumb

.thumb_func
.globl XPUT32
XPUT32:
    push {lr}
    ;@ call an arm function from thumb asm
    ldr r2,=PUT32
    mov lr,pc
    bx r2
    pop {r2}
    bx r2

mostly the same except you cannot pop to lr in thumb mode, you can pop to pc, but I dont think that switches modes, so you cant use it, you again need a spare register. You of course need to know the calling conventions to know what registers you can use or you can wrap another set of pushes and pops to preserve all but lr

    push {r2,lr}
    ;@ call an arm function from thumb asm
    ldr r2,=PUT32
    mov lr,pc
    bx r2
    pop {r2}
    mov lr,r2
    pop {r2}
    bx lr

Thumb to thumb or arm to arm you just use a bl if you can reach. ldr pc,address if you cant.

以为你会在 2025-01-04 07:11:59

如果将 asm 代码汇编为 Thumb,则需要将该函数标记为 Thumb 函数,以便链接器在分支到它时使用正确的指令(例如,BLX 或 BX 到设置了低位的地址)。这是通过 .thumb_func 指令完成的:

.global activate
.thumb_func
activate:
    b test

另一个选项是显式要求汇编器生成 ARM 代码:

.code 32
.global activate
activate:
    b test

检查 这篇文章 也是如此,但请记住,当前的处理器不需要许多解决方法,而这些解决方法是ARMv4,所以你可能不应该盲目遵循它。

If you assemble your asm code as Thumb, you need to mark the function as a Thumb function, so that the linker uses correct instruction when branching to it (e.g. BLX or BX to an address with the low bit set). This is done with the .thumb_func directive:

.global activate
.thumb_func
activate:
    b test

Another option is to explicitly ask the assembler to generate ARM code:

.code 32
.global activate
activate:
    b test

Check this article too, although remember that current processors don't need many workarounds that were necessary in ARMv4, so you probably shouldn't follow it blindly.

骷髅 2025-01-04 07:11:59

为了消除混乱:

问题是 Ubuntu 的 ARM GCC 交叉编译器默认生成拇指(16 位)指令。正如这里的其他答案所示,两者之间的调用是可能的,但是当 GNU 汇编器检测到 C 代码正在生成拇指指令时,因此很高兴使用 bx 生成垫片来正确设置调用 C 的模式,我无法控制 GCC 本身为调用函数生成的内容,并且它仅使用 bl 来调用它们,这会破坏,因为我的汇编代码需要是 ARM 指令(32 位)。

解决方案(文档很少)是发送 gcc -marm,这至少会使所有代码具有相同的类型。

如果有一个开关可以让 gcc 生成函数的 bx 调用,那也可能有效。

To eliminate the confusion:

The problem was that Ubuntu's GCC cross-compiler for ARM generates thumb (16-bit) instructions by default. As other answers here show, calling between the two is possible, but while the GNU assembler detected that the C code was generating thumb instructions and so happily generated shims using bx to set the mode correctly for calling into C, I have no control over what GCC itself generates for calling functions, and it was calling them with just bl, which broke because my assembly code needs to be ARM instructions (32-bit).

The solution (which is poorly documented) is to send gcc -marm, which will at least make all the code the same type.

If there is a switch to get gcc to generate bx calls for functions, that would probably work as well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文