gcc - 裸机 mod (%) 在带有 libgcc 的 ARMv6 上挂起

标签 gcc arm qemu armv6 libgcc

当我尝试在 ARM 裸机程序中的 C 代码中使用 % 时,它需要 libgcc 的包装器。没问题,我可以链接它。当我这样做时,链接器停止提示,但是程序在 mod 使用时挂起(如果我观察寄存器,它们实际上开始以莫名其妙的方式循环)。用 % 注释掉该行会使程序不会以这种方式挂起,所以这肯定是问题所在。

我在 https://gist.github.com/1724746 构建了一个简单的问题示例。

我使用以下方式运行测试:

qemu-system-arm -M versatilepb -cpu arm1176 -nographic -kernel kernel.elf | xxd

然后 ^a-x 退出它,并注释掉 % 行,我得到了我期望的输出字节,但是使用那里的行我没有得到任何这样的输出。

知道这里发生了什么吗?

编辑:我使用的交叉编译器是 Ubuntu 上的默认设置:https://launchpad.net/gcc-linaro

最佳答案

所以它用 2 加载 r0 和 r1(它对当前任务+1 执行加一操作

10648:  e1a00003    mov r0, r3
1064c:  e51b1010    ldr r1, [fp, #-16]
10650:  eb00fd36    bl  4fb30 <____aeabi_uidivmod_veneer>

我猜他们用_veneer从 ARM 切换到拇指,它是一个切换模式的蹦床:

0004fb30 <____aeabi_uidivmod_veneer>:
   4fb30:   e51ff004    ldr pc, [pc, #-4]   ; 4fb34 <____aeabi_uidivmod_veneer+0x4>
   4fb34:   00010905    .word   0x00010905

这将带您到这里,实际的模运算,这是拇指代码,拇指模式

00010904 <__aeabi_uidivmod>:
   10904:   2900        cmp r1, #0
   10906:   d0f8        beq.n   108fa <__aeabi_uidiv+0x252>
   10908:   e92d 4003   stmdb   sp!, {r0, r1, lr}
   1090c:   f7ff fecc   bl  106a8 <__aeabi_uidiv>
   10910:   e8bd 4006   ldmia.w sp!, {r1, r2, lr}
   10914:   fb02 f300   mul.w   r3, r2, r0
   10918:   eba1 0103   sub.w   r1, r1, r3
   1091c:   4770        bx  lr
   1091e:   bf00        nop

所以它看起来会进行正常的除法,然后将结果相乘并相减

12345 % 100 = 12345 - ((12345/100)*100) = 12345 - (123*100) = 12345 - 12300 = 45

我想知道问题是否出在拇指模式上。 arm1176肯定有thumb模式,真正的,而且我qemu可以做thumb。

你可以尝试一个实验来找出汇编和链接:

.thumb
.thumb_func
.globl thumb_test
thumb_test:
   add r0,#1
   bx lr

arm-none-linux-gnueabi-as thumb_test.s -o thumb_test.o

或者任何你的工具链前缀(如果有),并将 .o 文件与其他所有内容链接起来。

在C代码中将其声明为

unsigned int thumb_test ( unsigned int );

无论你传递什么,你都应该得到该值加一……尝试这个而不是模数。

要尝试的另一件事是直接除法,看看除法是否有效但不能取模,也许问题在于乘法指令?谁知道呢。

嗯嗯,我想我看到了问题:

0004fb30 <____aeabi_uidivmod_veneer>:
   4fb30:   e51ff004    ldr pc, [pc, #-4]   ; 4fb34 <____aeabi_uidivmod_veneer+0x4>
   4fb34:   00010905    .word   0x00010905

您无法使用 ldr 切换模式,它必须是 bx 或 blx,当它尝试在 Arm 模式下执行拇指代码时,它可能会转到未定义的处理程序。

我有一些关于切换模式如何工作的示例,特别是为 qemu 编写的。现在这是一个低级示例,例如没有 printf,我确实有 uart 输出,可以通过一种方式查看 uart 上的内容。如果这是问题所在(切换到拇指模式),那么您需要检查如何编译和链接程序。如果您不使用以前的代码源(现在由导师图形使用)工具链,您可能需要指定交互工作,或者可能需要了解工具链的构建方式。假设您正在使用基于 gnu/gcc 的东西。

如果你有办法在其中放置一个未定义的处理程序,或者如果你能够观察跟踪并看到 pc 下降到地址 0x0000000 附近的某个位置,那么这可能就是正在发生的情况。如果你用我的小拇指测试东西构建,并且它使用 ldr 而不是 bx 来到达那里,那么这应该不起作用,它仍然应该崩溃......

关于gcc - 裸机 mod (%) 在带有 libgcc 的 ARMv6 上挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9117046/

相关文章:

assembly - 我无法理解 ARM 堆栈操作是如何工作的

gcc - 对 `__aeabi_ddiv'和 friend 的 undefined reference -在没有stdlib的情况下使用-mfloat-abi = hard进行构建

sockets - qemu/kvm : cannot connect multiple machines to the same socket

gcc - 如何在构建目标之外生成 gcc 调试符号?

gcc - 你如何解释gcc对i386的IN、OUT指令的内联汇编约束?

c - 如何在未对齐的缓冲区中使用结构

assembly - 如何使用 rdtsc 在 Qemu i386 系统中进行基准测试

c - 使用 const 外部值作为非常量外部值是否安全?

c - 调用带有太多参数的函数时的 GCC 行为

c - 使用带有 virtio 设备/驱动程序的 virtqueue 从主机到 guest 时清空缓冲区