【问题标题】:Compiling and running ARM assembly binary on Cortex-M4 (simulated in QEMU)在 Cortex-M4 上编译和运行 ARM 汇编二进制文件(在 QEMU 中模拟)
【发布时间】:2017-09-09 08:16:31
【问题描述】:

我使用这个过程在虚拟QEMU嵌入式系统connex上成功编译并执行了ARM二进制文件:

arm-none-eabi-as -o program.o program.s
arm-none-eabi-ld -Ttext=0x0 -o program.elf program.o  
arm-none-eabi-objcopy -O binary program.elf program.bin
dd if=/dev/zero of=flash.bin bs=4096 count=4096
dd if=program.bin of=flash.bin bs=4096 conv=notrunc
qemu-system-arm -M connex -pflash flash.bin -nographic -serial /dev/null

在第四行,我创建了一个归零的空磁盘,代表闪存,在第五行,我将二进制文件复制到闪存中。

所以这就像一个魅力,但它模拟了整个嵌入式系统,而我只想模拟 ARM 内核,例如 Cortex-M4。这就是为什么我试图只使用qemu-arm 而不是qemu-system-arm

所以我第一次尝试像这样编译和运行我的程序(第 1-3 行与上面相同):

arm-none-eabi-as -o program.o program.s
arm-none-eabi-ld -Ttext=0x0 -o program.elf program.o  
arm-none-eabi-objcopy -O binary program.elf program.bin
qemu-arm -cpu cortex-m4 program.bin

这不起作用 - 它说:

Error while loading program.bin: Exec format error

所以我尝试像以前一样创建 Flash 图像(因为它有效):

arm-none-eabi-as -o program.o program.s
arm-none-eabi-ld -Ttext=0x0 -o program.elf program.o  
arm-none-eabi-objcopy -O binary program.elf program.bin
dd if=/dev/zero of=flash.bin bs=4096 count=4096
dd if=program.bin of=flash.bin bs=4096 conv=notrunc
qemu-arm -cpu cortex-m4 flash.bin

我明白了:

Error while loading flash.bin: Permission denied

谁能帮帮我?使用 sudo 没有帮助。

【问题讨论】:

  • qemu-arm 将在 ARM 模式下启动,如果 ELF 入口点清除了低位,如果入口点设置了低位,则以 Thumb 模式启动(Thumb 模式 ELF 文件的通常约定)。对于 M 配置文件核心,如果您尝试在未设置 CPSR.T 的情况下执行任何操作,您将立即收到 UsageFault(在 qemu-arm 中可能会表现为尝试传递 SIGILL)。它实际上不会像 ARM 指令那样执行任何东西,尽管调试日志反汇编器可能仍然会反汇编 ARM 格式的 insn。

标签: arm qemu cortex-m


【解决方案1】:

qemu-arm 的目的不是“模拟一个 ARM 内核”。它是“运行单个 Linux 二进制文件”,它希望您提供的二进制文件是 Linux 格式的 ELF 可执行文件。试图喂它别的东西是行不通的。

由于 Linux 采用 A-profile 内核,而不是 M-profile 内核,因此您在 qemu-arm 上使用 -cpu cortex-m4 所做的任何事情都只能靠运气,而不是故意的。 (我们不会禁用这些 CPU 类型,因为有一些 GCC 测试用例场景使用半主机,我们不想故意破坏这些类型的工作。但这些工作与其他任何事情一样幸运。)

【讨论】:

  • 为什么 qemu-arm 有各种各样的 cortex-m 核心,而 qemu-system-arm 没有?两者之间是否没有联系(qemu-arm 是否使用与 qemu-system-arm 不同的代码/内核)?
  • qemu-system-arm 支持同一组 CPU,包括 cortex-m3 和 cortex-m4。如果您的 qemu-system-arm 没有列出 cortex-m3,那么它一定是一个非常旧的版本(十年或更长时间)。或者它可能是一个特定于发行版的特殊功能,禁用了很多代码——我认为 RedHat 有一个用于运行 ARM 虚拟机的功能,其中大多数仅仿真内核都被禁用以最大程度地减少安全攻击面。
  • 上次我检查没有一个系统有 cortex-m4 或任何 (M) 但 cortex-m3,正如所指出的......有一个叉子可以利用它们,是的.
  • qemu 中的 cortex-m3 直到最近才被修复为不会被破坏,所以即使它是在 tiva c 被称为 Stellaris 时添加的,并且在 texas 仪器吸收它们之前来自 luminary micro。实际上,他们是第一个在硅中拥有 m3 的人(用于大规模消费),并且 qemu 后端走得那么远,但已经有那么久了。谁知道不尝试 m4 等 qemu 目标也可能是错误的,直到有人去实际尝试它们。
  • 是的,我们有 m4 CPU 支持,但还没有 M4 的板模型。将 -cpu cortex-m4 传递给其中一个 Stellaris 板可能会产生类似的科学怪人东西。
【解决方案2】:

与微控制器构建相比,您需要一个入口点(并且它是 ram)。

开始.s

.thumb
.thumb_func
.global _start
_start:
    @mov r0,=0x10000
    @mov sp,r0
    bl notmain
    mov r7,#0x1
    mov r0,#0
    swi #0
.word 0xFFFFFFFF
    b .

.thumb_func
.globl PUT32
PUT32:
    str r1,[r0]
    bx lr

.thumb_func
.globl GET32
GET32:
    ldr r0,[r0]
    bx lr

.thumb_func
.globl dummy
dummy:
    bx lr

.thumb_func
.globl write
write:
    push {r7,lr}
    mov r7,#0x04
    swi 0
    pop {r7,pc}
    b .

.end

notmain.c

void PUT32 ( unsigned int, unsigned int );
unsigned int GET32 ( unsigned int );
void dummy ( unsigned int );
void write ( unsigned int, char *, unsigned int );
int notmain ( void )
{
    //unsigned int ra;
    //for(ra=0;ra<1000;ra++) dummy(ra);
    write(1,"Hello\n",6);
    return(0);

}

你好.ld

ENTRY(_start)
MEMORY
{
    ram : ORIGIN = 0x00010000, LENGTH = 0x1000
}
SECTIONS
{
    .text : { *(.text*) } > ram
    .rodata : { *(.rodata*) } > ram
    .bss : { *(.bss*) } > ram
}

构建

arm-none-eabi-as --warn --fatal-warnings start.s -o start.o
arm-none-eabi-gcc -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding  -mthumb -c notmain.c -o notmain.o
arm-none-eabi-ld -o notmain.elf -T hello.ld start.o notmain.o
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy notmain.elf notmain.bin -O binary

运行

qemu-arm -d in_asm,cpu,cpu_reset -D hello -cpu cortex-m4 notmain.elf 
Hello

转储日志

cat hello
CPU Reset (CPU 0)
R00=00000000 R01=00000000 R02=00000000 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00000000 R11=00000000
R12=00000000 R13=00000000 R14=00000000 R15=00000000
PSR=40000000 -Z-- A usr26
CPU Reset (CPU 0)
R00=00000000 R01=00000000 R02=00000000 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00000000 R11=00000000
R12=00000000 R13=00000000 R14=00000000 R15=00000000
PSR=40000010 -Z-- A usr32
Reserved 0xf7000000 bytes of guest address space
host mmap_min_addr=0x10000
guest_base  0x7f4347fb4000
start    end      size     prot
00010000-00011000 00001000 r-x
f67ff000-f6800000 00001000 ---
f6800000-f7000000 00800000 rw-
start_brk   0x00000000
end_code    0x00010044
start_code  0x00010000
start_data  0x00010044
end_data    0x00010044
start_stack 0xf6fff350
brk         0x00010044
entry       0x00010001
----------------
IN: 
0x00010000:  f000 f810  bl  0x10024

R00=00000000 R01=f6fff4c2 R02=00000000 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00010044 R11=00000000
R12=00000000 R13=f6fff350 R14=00000000 R15=00010000
PSR=00000030 ---- T usr32
----------------
IN: notmain
0x00010024:  b508       push    {r3, lr}
0x00010026:  2001       movs    r0, #1
0x00010028:  4903       ldr r1, [pc, #12]   (0x10038)
0x0001002a:  2206       movs    r2, #6
0x0001002c:  f7ff fff5  bl  0x1001a

R00=00000000 R01=f6fff4c2 R02=00000000 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00010044 R11=00000000
R12=00000000 R13=f6fff350 R14=00010005 R15=00010024
PSR=00000030 ---- T usr32
----------------
IN: 
0x0001001a:  b580       push    {r7, lr}
0x0001001c:  2704       movs    r7, #4
0x0001001e:  df00       svc 0

R00=00000001 R01=0001003c R02=00000006 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00010044 R11=00000000
R12=00000000 R13=f6fff348 R14=00010031 R15=0001001a
PSR=00000030 ---- T usr32
----------------
IN: 
0x00010020:  bd80       pop {r7, pc}

R00=00000006 R01=0001003c R02=00000006 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000004
R08=00000000 R09=00000000 R10=00010044 R11=00000000
R12=00000000 R13=f6fff340 R14=00010031 R15=00010020
PSR=00000030 ---- T usr32
----------------
IN: notmain
0x00010030:  2000       movs    r0, #0
0x00010032:  bc08       pop {r3}
0x00010034:  bc02       pop {r1}
0x00010036:  4708       bx  r1

R00=00000006 R01=0001003c R02=00000006 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00010044 R11=00000000
R12=00000000 R13=f6fff348 R14=00010031 R15=00010030
PSR=00000030 ---- T usr32
----------------
IN: 
0x00010004:  2701       movs    r7, #1
0x00010006:  2000       movs    r0, #0
0x00010008:  df00       svc 0

R00=00000000 R01=00010005 R02=00000006 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00010044 R11=00000000
R12=00000000 R13=f6fff350 R14=00010031 R15=00010004
PSR=40000030 -Z-- T usr32

如果你触摸堆栈指针会不高兴,所以不要......

感谢您指出这个程序,不知道它,将有一些乐趣......

编辑

抱歉,您只是想要组装。

开始.s

.thumb
.thumb_func
.global _start
_start:
    mov r4,#10
top:
    nop
    sub r4,#1
    bne top

    mov r7,#0x1
    mov r0,#0
    swi #0
.word 0xFFFFFFFF
    b .

.end

上面的链接器脚本

构建

arm-none-eabi-as --warn --fatal-warnings start.s -o start.o
arm-none-eabi-ld -o notmain.elf -T hello.ld start.o
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy notmain.elf notmain.bin -O binary

运行

qemu-arm -d in_asm,cpu,cpu_reset -D hello -cpu cortex-m4 notmain.elf 

转储日志

cat hello
CPU Reset (CPU 0)
R00=00000000 R01=00000000 R02=00000000 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00000000 R11=00000000
R12=00000000 R13=00000000 R14=00000000 R15=00000000
PSR=40000000 -Z-- A usr26
CPU Reset (CPU 0)
R00=00000000 R01=00000000 R02=00000000 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00000000 R11=00000000
R12=00000000 R13=00000000 R14=00000000 R15=00000000
PSR=40000010 -Z-- A usr32
Reserved 0xf7000000 bytes of guest address space
host mmap_min_addr=0x10000
guest_base  0x7f36110fc000
start    end      size     prot
00010000-00011000 00001000 r-x
f67ff000-f6800000 00001000 ---
f6800000-f7000000 00800000 rw-
start_brk   0x00000000
end_code    0x00010014
start_code  0x00010000
start_data  0x00010014
end_data    0x00010014
start_stack 0xf6fff350
brk         0x00010014
entry       0x00010001
----------------
IN: 
0x00010000:  240a       movs    r4, #10
0x00010002:  46c0       nop         (mov r8, r8)
0x00010004:  3c01       subs    r4, #1
0x00010006:  d1fc       bne.n   0x10002

R00=00000000 R01=f6fff4c2 R02=00000000 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00010014 R11=00000000
R12=00000000 R13=f6fff350 R14=00000000 R15=00010000
PSR=00000030 ---- T usr32
----------------
IN: 
0x00010002:  46c0       nop         (mov r8, r8)
0x00010004:  3c01       subs    r4, #1
0x00010006:  d1fc       bne.n   0x10002

R00=00000000 R01=f6fff4c2 R02=00000000 R03=00000000
R04=00000009 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00010014 R11=00000000
R12=00000000 R13=f6fff350 R14=00000000 R15=00010002
PSR=20000030 --C- T usr32
R00=00000000 R01=f6fff4c2 R02=00000000 R03=00000000
R04=00000008 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00010014 R11=00000000
R12=00000000 R13=f6fff350 R14=00000000 R15=00010002
PSR=20000030 --C- T usr32
----------------
IN: 
0x00010008:  2701       movs    r7, #1
0x0001000a:  2000       movs    r0, #0
0x0001000c:  df00       svc 0

R00=00000000 R01=f6fff4c2 R02=00000000 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00010014 R11=00000000
R12=00000000 R13=f6fff350 R14=00000000 R15=00010008
PSR=60000030 -ZC- T usr32

【讨论】:

  • 重新阅读你想要组装的标题,删除 bl notmain 和 gcc 部分。
  • 这是从 M 配置文件代码进行 Linux 系统调用,这只是偶然地真正起作用,据我所知,它不对应于任何真实硬件 RTOS 的代码......你会在我看来,最好使用 qemu-system-arm 和半主机(或与 UART 对话)。在 qemu-arm 中没有中断控制器,没有访问任何内存映射的系统寄存器,没有异常处理,也没有 UART 或定时器设备。这些对于 M-profile 代码都非常重要。
  • 如果你想使用 cortex-m4 或其他(m3 除外)还没有选择使用 qemu-system-arm,这是一个更大的项目去编写一个系统将其添加到 qemu-system-arm 以使用此模拟器。
  • 绝不是一种意外,一个调用就是一个调用,它们并没有什么神奇之处,Linux 就是这样的指令集合。我本可以把电话放在外面,添加它们是为了好玩。 OP 想知道如何执行此操作,您提供了缺少的链接
  • 就像我说的那样,它的出现是偶然的,因为我们不想故意破坏 GCC 测试套件和其他碰巧发现它适用于他们有限目的的用户。这不是一个很大的错误,因为所有应该可以正常工作的东西。我们只是碰巧没有尽我们所能很好地诊断用户错误。
猜你喜欢
  • 2018-05-17
  • 2022-07-25
  • 1970-01-01
  • 1970-01-01
  • 2014-05-04
  • 2016-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多