【问题标题】:Segmentation Fault - ARM Assembly分段错误 - ARM 程序集
【发布时间】:2013-07-04 09:02:25
【问题描述】:

我正在尝试将ARM 寄存器(R0) 指向的数据加载到另一个寄存器(R1)

所以,我正在使用LDR R1,[R0]。 但是R0 是一个立即值,例如 LDR R0,=0x0804c000

我遇到了分段错误。

注册信息

(gdb) info registers
r0             0x804c000        134529024
r1             0x1      1
r2             0x804c044        134529092
r3             0x1      1
r4             0x804c088        134529160
r5             0x0      0
r6             0x804c0cc        134529228
r7             0xbe9746c4       3197585092
r8             0x804c110        134529296
r9             0x8fb9   36793
r10            0x804c154        134529364
r11            0x0      0
r12            0x0      0
sp             0xbe9746c4       0xbe9746c4
lr             0x8939   35129
pc             0x89f0   0x89f0 <test46+48>
cpsr           0x60000030       1610612784

Disassembler:

(gdb) disassemble
Dump of assembler code for function test46:
   0x000089c0 <+0>:     push    {r7}
   0x000089c2 <+2>:     add     r7, sp, #0
   0x000089c4 <+4>:     ldr     r0, [pc, #60]   ; (0x8a04)
   0x000089c6 <+6>:     ldr     r2, [pc, #64]   ; (0x8a08)
   0x000089c8 <+8>:     ldr     r4, [pc, #64]   ; (0x8a0c)
   0x000089ca <+10>:    ldr     r6, [pc, #68]   ; (0x8a10)
   0x000089cc <+12>:    ldr.w   r8, [pc, #68]   ; 0x8a14
   0x000089d0 <+16>:    ldr.w   r10, [pc, #68]  ; 0x8a18
   0x000089d4 <+20>:    nop
   0x000089d6 <+22>:    nop
   0x000089d8 <+24>:    nop
   0x000089da <+26>:    nop
   0x000089dc <+28>:    nop
   0x000089de <+30>:    nop
   0x000089e0 <+32>:    nop
   0x000089e2 <+34>:    nop
   0x000089e4 <+36>:    nop
   0x000089e6 <+38>:    nop
   0x000089e8 <+40>:    nop
   0x000089ea <+42>:    nop
   0x000089ec <+44>:    nop
   0x000089ee <+46>:    nop
=> 0x000089f0 <+48>:    ldr     r1, [r0, #0]
   0x000089f2 <+50>:    ldr     r3, [r2, #0]
   0x000089f4 <+52>:    ldr     r5, [r4, #0]
   0x000089f6 <+54>:    ldr     r7, [r6, #0]
   0x000089f8 <+56>:    ldr.w   r9, [r8]
   0x000089fc <+60>:    ldr.w   r11, [r10]
   0x00008a00 <+64>:    b.n     0x89f0 <test46+48>
End of assembler dump.

LDR指令不能这样用吗?我可以使用以下命令将数据从 R0 移动到 R1 没有任何问题MOV R1, R0

这是我的compilation flags:

gcc -std=c99 -mthumb -march=armv7 -mthumb-interwork -static -ffunction-sections

【问题讨论】:

  • 我没想到你可以直接访问缓存并读取它。你用的是什么处理器?你能指点我的数据表吗?
  • http://www.arndaleboard.org/wiki/index.php/Main_Page
  • 你想做什么?即,总体目的或目标是什么?你只是在玩汇编程序还是真的在尝试做某事?如果是这样,你能描述一下吗?

标签: gcc assembly arm


【解决方案1】:

从您的一个 cmets 在另一个响应中判断,我认为您对缓存如何工作的看法是错误的。我不相信支持缓存的内存可以直接访问,并且查看数据表,我会说我是正确的。用于缓存的 RAM 通常非常快,如果您可以避免尝试访问主存储器时所涉及的典型地址周期,则它的运行效果最好。此外,内核不允许直接访问 L1 的内容,因为它可能会给系统带来很多麻烦,即使您只能读取它而不写入它——想想另一个可以检查 L1 的用户空间进程。内容并可能从中提取密码或其他敏感数据。通常,您通过系统协处理器执行影响缓存的操作,您需要在ARM Architecture Manual for the Cortex-A15 中阅读。

即使您可以直接访问它,您也忘记了其中涉及 MMU 和 Linux。 Linux 设置的虚拟内存空间看起来与处理器的物理空间大不相同。在这种情况下,0x0804c000 未映射,因此会出现分段错误。

我怀疑这个问题只是一个编码错误。 FWIW,您提供的 sn-p 看起来是正确的,只是您正在访问无效的内存位置。

【讨论】:

  • 谁说过 Linux 参与其中?为什么他不能直接访问内存映射的缓存寄存器?谁说他用的是 A15,即使他是,谁说什么味道?
  • 哦,等等,我现在看到了 arndaleboard 参考。
  • 是的,假设代码在特权模式(内核或模块)下运行,那么物理地址在访问之前需要映射到未缓存的虚拟地址。
  • 缓存无关;这个答案并不完全有意义。如果内存不可访问,缓存如何填充该值? cache 是不合理的。仅当您可以直接填充(并锁定)缓存 时才有意义。否则,缓存应该是物理/虚拟内存的副本。如果物理内存不可访问,那么缺少任何缓存操作原语,它也不会在缓存中。对于 99% 的代码,Linux 并不关心 缓存
  • 然后再读一遍。 OP 认为您可以直接访问 L1 并且可以读取缓存行。我是说你没有,即使你可以,这个想法也被打破了。
【解决方案2】:

该指令LDR R1, [R0]R0 获取一个地址,并将一个32 位整数从该地址加载到R1

如果R0 中的地址不是有效地址,则会出现分段错误。您应该在该指令上设置一个断点,然后查看 R0 中的内容。

(gdb) break *0x000089f0
(gdb) run
<program hits breakpoint>
(gdb) info registers
<read value from R0>

然后您可以尝试使用调试器从该地址加载,看看它是否在那里工作:

(gdb) x/x $r0

如果调试器可以读取地址,那么问题就不是你想象的那样;形成另一个假设并对其进行检验。

【讨论】:

  • R0的值为0x0804c000
  • 嗯,这是一个有效的地址吗?
  • 它指向一个缓存行。所以,是的,这是一个有效的地址。
  • (gdb) x/x $r0 0x804c000: Cannot access memory at address 0x804c000
  • 是设备寄存器?寄存器的宽度是多少?您可能需要使用字节加载?
猜你喜欢
  • 2016-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-13
  • 2022-01-17
  • 1970-01-01
  • 2015-09-15
相关资源
最近更新 更多