assembly QEMU中的裸机ARM str指令行为

jaxagkaj  于 2023-08-06  发布在  其他
关注(0)|答案(2)|浏览(114)

说明

我正在尝试构建一个裸机应用程序(无操作系统,无引导加载程序)并在QEMU中运行它,但我发现str指令似乎没有任何作用,出现了一些奇怪的行为。

对于某些上下文,我只想将程序直接注入RAM并运行它。我使用了一个经过修改的裸机linkerstartup.S作为内存布局和C环境设置的示例。我并不关心我使用的是哪个ARM平台,所以我使用了他们示例中的同一个平台,即采用cortex-a9处理器的vexpress-a9。
我修改了启动文件,以便直接在0x0的启动异常向量处开始执行(我将其视为ROM,尽管我知道它不是)。我们的想法是把.text部分放在这里,一些设置碰巧设置了.data.bss和堆栈,然后我分支到main

MEMORY
{
    ROM (rx) : ORIGIN = 0x00000000, LENGTH = 1M
    RAM (rwx): ORIGIN = 0x00400000, LENGTH = 4M
}

字符串
这实际上是可行的,因为我可以启动QEMU,附加一个gdb会话,并逐步执行初始化代码,但对于应该在“RAM”中进行的设置(从0x00400000开始),根本没有初始化任何内容。
对于下面的部分汇编,我的想法是用0xFEFEFEFE填充FIQ堆栈部分。因此,我将r1设置为堆栈的开始,将sp设置为堆栈的结束,当r1 <sp时,我使用r0中的值填充r1中包含的地址,并将r1中的地址递增4个字节。

Reset_Handler:
    /* FIQ stack */
    msr cpsr_c, MODE_FIQ
    ldr r1, =_fiq_stack_start
    ldr sp, =_fiq_stack_end
    movw r0, #0xFEFE
    movt r0, #0xFEFE

fiq_loop:
    cmp r1, sp
    strlt r0, [r1], #4   <<<< ISSUE HERE
    blt fiq_loop


对于正确的迭代次数(堆栈大小),这确实可以正确地循环,但对于strlt r0, [r1], #4指令,* 什么都没有发生 *。
如果我在str指令之前检查,r1是堆栈的开始,值是0x0

>>> p/x $r1                                                                                                                   
$2 = 0x400008                                                                                                                 
>>> x/2hx $r1                                                                                                                 
0x400008:       0x0000  0x0000


跳过str指令后,r1移动了4个字节,但堆栈开始处的内存仍然是0x0

>>> p/x $r1                                                                                                                   
$3 = 0x40000c 
>>> x/2hx 0x400008                                                                                                            
0x400008:       0x0000  0x0000


内存不会更新,但我 * 可以 * 直接在那里设置值,因此我知道它 * 可以 * 更新:

>>> set *(0x400008)=0x12345678                                                                                                
>>> x/2hx 0x400008                                                                                                            
0x400008:       0x5678  0x1234


我用以下命令启动qemu:

qemu-system-arm \
        -nographic \
        -s \
        -S \
        --no-reboot \
        -machine vexpress-a9 \
        -cpu cortex-a9 \
        -m 12M \
        -device loader,file=out.elf


我已经使用-mcpu=cortex-a9选项进行了编译,并且相信我已经为QEMU提供了足够的RAM。我真的不知道这里发生了什么,任何帮助都是感激不尽的。

进一步调试

根据要求,我还对以下实体的状态进行了澄清:

  • _fiq_stack_start的值是什么?

0x00400008 <-这是我所期望的,因为我期望fiq堆栈在.data部分之后开始,该部分包含8个字节

  • _fiq_stack_end的值是多少?

0x00401008 <-这是我所期望的,因为我指定堆栈为4096字节

  • cmp指令执行时r1的内容是什么?

r1 = 0x00400008 <-这是我所期望的,因为r1应该包含堆栈的开始。

  • sp寄存器的内容是什么?

0x00401008 <-这是我所期望的,因为这应该是堆栈的结尾

  • strlt启动时的条件码位是什么?

在比较CPSR = 0x40000111之前和比较CPSR = 0x80000111之后。这是预期的,因为r1中的值小于sp的值,并且正符号比较的结果应将1置于位31中。

  • r0的内容是什么呢?

0xfefefefe <-根据两条mv指令,这是我所期望的,用我想在堆栈中的值填充r0寄存器。

  • 如果将strlt更改为str,会发生什么情况?

实际上我已经测试过了,我得到了同样的行为。
我也尝试过这些简单的指令:

mov r0, #0x1234
    mov r3, #0x2
    str r0, [r3] /* Store value of R0 into addr at r3 */


在单步执行每条指令之后,我希望将r0中保存的值0x1放入r3中保存的0x2的内存地址中。但经过检查却不是。

>>> p/x $r0
$7 = 0x1

>>> p/x $r3
$8 = 0x2

>>> x/2hx $r3
0x2 <_Reset+2>: 0xea00  0x0041


这就好像str指令被完全忽略了。

lnvxswe2

lnvxswe21#

“当我试图存储到内存中时,就好像什么都没有发生”几乎总是意味着“我试图存储到实际上没有RAM的地方”。有时这是“什么都没有”,有时这是“有闪存或ROM在那里,所以写入被忽略”。根本原因通常是“程序链接到错误的地址”。
这些地址:

ROM (rx) : ORIGIN = 0x00000000, LENGTH = 1M
RAM (rwx): ORIGIN = 0x00400000, LENGTH = 4M

字符串
与vexpress-a9的QEMU型号不匹配。第一个是可以的(地址0是可重Map区域,QEMU将其建模为“始终是闪存,而不是客户运行时可配置的”),但是在0x 00400000处没有RAM--这个地址在闪存内部,所以它不像RAM那样可写。
您应该使用链接器Map,将RAM区域放置在内存Map称为“Local DDR2”的区域中,该区域从0x6000_0000开始。您开始的教程中的链接器脚本可以正确地实现这一点,因为它使用了0x6000_0000和0x7000_0000 --尽管注意,这只是因为该教程中的文档说使用-m 512 M,它提供了足够的RAM来达到0x7000_0000内存范围。
您的链接器脚本碰巧在xilinx-zynq-a9板上工作的原因是,该板将其RAM块放在地址0。
这里我认为重要的是要理解的是,当你写一个链接器脚本时,你不能随意选择地址。必须编写链接器脚本,以匹配您要在其上运行结果裸机二进制文件的电路板的地址Map,然后该二进制文件将不会在不同的电路板类型上运行。
(顺便说一句,这块板上有一个QEMU错误,我们试图在地址0MapRAM和闪存--我认为闪存实际上“赢了”,所以结果是低地址区域是闪存。)

biswetbf

biswetbf2#

我找到了一个答案,并让它工作。我从使用vxexpress-a9机器切换到使用xilinx-zynq-a9机器(一种不同的cortex-a9设备),一切都开始工作了。所以我现在开始:

qemu-system-arm \
        -nographic \
        -s \
        -S \
        --no-reboot \
        -machine xilinx-zynq-a9 \
        -cpu cortex-a9 \
        -m 12M \
        -device loader,file=out.elf

字符串
我相信问题是我在重置向量处直接将.elf注入内存,就像我想要的那样,但是对于vxexpress-a9板来说,这可能无效。I found a memory map description,这表明我使用的内存部分可以重新Map,所以也许它不是作为DDR2 RAM?也就是说,QEMU说它是doesn't model the SCC,这就是文档所说的允许配置该内存区域。老实说,我不是100%确定,但它似乎是我使用的设备。
我猜想,我正在使用的示例使用u-boot来设置硬件并从模拟的SD卡加载映像,这意味着它适用于该示例。这一定是模拟硬件所期望的,但我不想这样做。
x1c 0d1x的数据

相关问题