2012-01-21 144 views
7

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

我与objdump的观察到,当我做BL从组装到C代码(从_start)则产生一个小包装器,切换到拇指的指令。看起来,C代码全部是用拇指指令生成的,但是我的所有程序集都是在ARM(32位)指令中生成的。我无法弄清楚为什么这是或如何解决它。

+0

其中是该编译器从? –

+0

kernel.o :(。ARM.exidx + 0x0):未定义对'__aeabi_unwind_cpp_pr1'的引用 make:*** [kernel.elf] Error 1 –

+0

你是在试图构建一个arm linux应用程序吗?或嵌入式(无操作系统)应用程序?如果一个linux应用程序那么你不需要启动代码,工具链应该为你做所有这些,你担心main()作为你的入口点。 –

回答

5

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

实施例:

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

.type fn, %function 

fn: 
    mov pc, lr 
+0

谢谢!这似乎是完美的,并允许我链接库代码! – singpolyma

3

http://github.com/dwelch67/yagbat QEMU目录。

这里有一对夫妇从手臂调用手臂或拇指的例子

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是超前两个指令的指令的执行期间。对于拇指是4字节,对于手臂8字节。两种情况下的说明。为了模拟一个不能用来改变状态的BL,你需要加载带有返回地址的链接寄存器,并根据地址的ls位使用bx分支到函数改变状态。所以

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会调用一个蹦床函数。我仿照上面的一个模拟,你可以看到它有点浪费,希望我对编译器的解释只是为BL分配空间使得更清晰,浪费将是总是计划模式更改,并且必须为代码中的大部分函数调用插入nops。

代码还包括呼叫从拇指汇编手臂:

.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 

拇指以拇指或手臂武装你只需要使用一个BL如果你能达到。 ldr pc,地址如果你不能。

0

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

.global activate 
.thumb_func 
activate: 
    b test 

另一种选择是明确要求汇编程序生成的ARM代码:

.code 32 
.global activate 
activate: 
    b test 

检查this article过,但请记住,目前的处理器并不需要在在ARMv4是必要的许多变通方法,所以你可能不应该盲目追随它。

0

为了消除混乱:

的问题是,Ubuntu的GCC交叉编译为ARM默认生成拇指(16位)的指令。正如其他答案所示,两者之间的调用是可能的,但是虽然GNU汇编程序检测到C代码正在生成拇指指令,因此用bx快速生成垫片以正确设置调用 C的模式,但我无法控制通过GCC本身为调用函数生成的内容,并且它只是用bl来调用它们,因为我的汇编代码需要是ARM指令(32位),因此破坏了它们。

解决方案(文档记录不完善)是发送gcc -marm,它至少会使所有代码的类型相同。

如果有一个开关让gcc为函数生成bx调用,那可能也会起作用。

+0

gcc -marm不适用于我。我需要arm-v4t-linux-gnueabi的汇编代码 –