Cortex M33缺少矢量表
我想使用半粘附在QEMU中测试我的ARM项目。最初,我为Cortex A7和A9处理器构建,并且没有问题运行我的代码,但是现在我切换到CM33(和CM33板),它立即断开:
C:\Program Files\qemu>qemu-system-aarch64.exe -nographic -machine musca-a -cpu cortex-m33 -monitor none -serial stdio
-kernel app -m 512 -semihosting
qemu: fatal: Lockup: can't escalate 3 to HardFault (current priority -1)
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=ffffffe0 R14=fffffff9 R15=00000000
XPSR=40000003 -Z-- A S handler
FPSCR: 00000000
如果我理解正确,pc = 00000000
表示重置处理程序问题。我认为这也许这是musca-a
板期望该表在其他地方,但看起来完全缺少:
psykana@psykana-lap:~$ readelf app -S
There are 26 section headers, starting at offset 0xb1520:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .init PROGBITS 00008000 008000 00000c 00 AX 0 0 4
[ 2] .text PROGBITS 00008010 008010 01d5b4 00 AX 0 0 8
[ 3] .fini PROGBITS 000255c4 0255c4 00000c 00 AX 0 0 4
[ 4] .rodata PROGBITS 000255d0 0255d0 003448 00 A 0 0 8
[ 5] .ARM.exidx ARM_EXIDX 00028a18 028a18 000008 00 AL 2 0 4
[ 6] .eh_frame PROGBITS 00028a20 028a20 000004 00 A 0 0 4
[ 7] .init_array INIT_ARRAY 00038a24 028a24 000008 04 WA 0 0 4
[ 8] .fini_array FINI_ARRAY 00038a2c 028a2c 000004 04 WA 0 0 4
[ 9] .data PROGBITS 00038a30 028a30 000ad8 00 WA 0 0 8
[10] .persistent PROGBITS 00039508 029508 000000 00 WA 0 0 1
[11] .bss NOBITS 00039508 029508 0001c4 00 WA 0 0 4
[12] .noinit NOBITS 000396cc 000000 000000 00 WA 0 0 1
[13] .comment PROGBITS 00000000 029508 000049 01 MS 0 0 1
[14] .debug_aranges PROGBITS 00000000 029551 000408 00 0 0 1
[15] .debug_info PROGBITS 00000000 029959 02e397 00 0 0 1
[16] .debug_abbrev PROGBITS 00000000 057cf0 005b3e 00 0 0 1
[17] .debug_line PROGBITS 00000000 05d82e 01629f 00 0 0 1
[18] .debug_frame PROGBITS 00000000 073ad0 004bf4 00 0 0 4
[19] .debug_str PROGBITS 00000000 0786c4 006a87 01 MS 0 0 1
[20] .debug_loc PROGBITS 00000000 07f14b 01f27e 00 0 0 1
[21] .debug_ranges PROGBITS 00000000 09e3c9 009838 00 0 0 1
[22] .ARM.attributes ARM_ATTRIBUTES 00000000 0a7c01 000036 00 0 0 1
[23] .symtab SYMTAB 00000000 0a7c38 006ec0 10 24 1282 4
[24] .strtab STRTAB 00000000 0aeaf8 002927 00 0 0 1
[25] .shstrtab STRTAB 00000000 0b141f 000100 00 0 0 1
我正在使用以下选项进行构建(从我以前的问题):
add_compile_options(
-mcpu=cortex-m33
-specs=rdimon.specs
-O0
-g
-mfpu=fpv5-sp-d16
-mfloat-abi=hard
)
add_link_options(-specs=rdimon.specs -mcpu=cortex-m33 -mfpu=fpv5-sp-d16 -mfloat-abi=hard)
再次,这对我尝试过的所有处理器都很好,但是CM33中断了。实际上,它破坏了任何M核心和M核心QEMU董事会。
记录:
- arm-none-eabi-gcc (GNU Arm Embedded Toolchain 10.3-2021.10)
- QEMU emulator version 7.0.0 (v7.0.0-11902-g1d935f4a02-dirty)
- Microsoft Windows [Version 10.0.19044.1645]
- cmake version 3.22.
I want to test my ARM project within QEMU using semihosting. Initially I built for Cortex A7 and A9 processors and had no issues running my code, however now that I switched to CM33 (and a CM33 board), it breaks immediately:
C:\Program Files\qemu>qemu-system-aarch64.exe -nographic -machine musca-a -cpu cortex-m33 -monitor none -serial stdio
-kernel app -m 512 -semihosting
qemu: fatal: Lockup: can't escalate 3 to HardFault (current priority -1)
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=ffffffe0 R14=fffffff9 R15=00000000
XPSR=40000003 -Z-- A S handler
FPSCR: 00000000
If I understand it right, PC=00000000
indicates reset handler issues. I thought maybe this musca-a
board expects the table to be somewhere else, but looks like it's missing completely:
psykana@psykana-lap:~$ readelf app -S
There are 26 section headers, starting at offset 0xb1520:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .init PROGBITS 00008000 008000 00000c 00 AX 0 0 4
[ 2] .text PROGBITS 00008010 008010 01d5b4 00 AX 0 0 8
[ 3] .fini PROGBITS 000255c4 0255c4 00000c 00 AX 0 0 4
[ 4] .rodata PROGBITS 000255d0 0255d0 003448 00 A 0 0 8
[ 5] .ARM.exidx ARM_EXIDX 00028a18 028a18 000008 00 AL 2 0 4
[ 6] .eh_frame PROGBITS 00028a20 028a20 000004 00 A 0 0 4
[ 7] .init_array INIT_ARRAY 00038a24 028a24 000008 04 WA 0 0 4
[ 8] .fini_array FINI_ARRAY 00038a2c 028a2c 000004 04 WA 0 0 4
[ 9] .data PROGBITS 00038a30 028a30 000ad8 00 WA 0 0 8
[10] .persistent PROGBITS 00039508 029508 000000 00 WA 0 0 1
[11] .bss NOBITS 00039508 029508 0001c4 00 WA 0 0 4
[12] .noinit NOBITS 000396cc 000000 000000 00 WA 0 0 1
[13] .comment PROGBITS 00000000 029508 000049 01 MS 0 0 1
[14] .debug_aranges PROGBITS 00000000 029551 000408 00 0 0 1
[15] .debug_info PROGBITS 00000000 029959 02e397 00 0 0 1
[16] .debug_abbrev PROGBITS 00000000 057cf0 005b3e 00 0 0 1
[17] .debug_line PROGBITS 00000000 05d82e 01629f 00 0 0 1
[18] .debug_frame PROGBITS 00000000 073ad0 004bf4 00 0 0 4
[19] .debug_str PROGBITS 00000000 0786c4 006a87 01 MS 0 0 1
[20] .debug_loc PROGBITS 00000000 07f14b 01f27e 00 0 0 1
[21] .debug_ranges PROGBITS 00000000 09e3c9 009838 00 0 0 1
[22] .ARM.attributes ARM_ATTRIBUTES 00000000 0a7c01 000036 00 0 0 1
[23] .symtab SYMTAB 00000000 0a7c38 006ec0 10 24 1282 4
[24] .strtab STRTAB 00000000 0aeaf8 002927 00 0 0 1
[25] .shstrtab STRTAB 00000000 0b141f 000100 00 0 0 1
I'm building with the following options (modified toolchain file from my previous question):
add_compile_options(
-mcpu=cortex-m33
-specs=rdimon.specs
-O0
-g
-mfpu=fpv5-sp-d16
-mfloat-abi=hard
)
add_link_options(-specs=rdimon.specs -mcpu=cortex-m33 -mfpu=fpv5-sp-d16 -mfloat-abi=hard)
Again, this worked fine for all A processors I've tried, but breaks for CM33. In fact, it breaks for any M core and M core QEMU board.
For the record:
- arm-none-eabi-gcc (GNU Arm Embedded Toolchain 10.3-2021.10)
- QEMU emulator version 7.0.0 (v7.0.0-11902-g1d935f4a02-dirty)
- Microsoft Windows [Version 10.0.19044.1645]
- cmake version 3.22.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您的访客代码在启动时崩溃了,这几乎总是因为您的异常矢量表有问题。如果您使用QEMU的-D选项(例如-D CPU,INT,Guest_Errors,unimp,in_asm),这通常会提供有关究竟发生的事情的更多详细信息。
看着您的小精灵标头,看来您没有将矢量表放入二进制中。 QEMU需要此(就像实际硬件一样)。这样做的通常方法是拥有一个小汇编源文件,该文件将数据表列出具有各种异常入口点的地址的数据表,尽管还有其他方法可以做到这一点。 ( 。。
> 低地址。在M profile重置上,通过从矢量表中读取初始PC和SP值,而异常处理程序也从矢量表中读取。 (也就是说,在A Profile上,Magic Low地址的事物是代码,在M profile上,它是数据,有效地功能指针)。
还要注意,QEMU-KERNEL选项的行为在A Profile和M profile之间有所不同:在A Profile上,它将将ELF文件加载到内存中并尊重Elf入口点(执行将从那里开始)。在M profile上,它将加载ELF文件,然后以硬件指定方式从重置启动CPU,即不设置PC到ELF入口点。 (这种变化本质上是出于历史/背面的原因。)如果您想“只加载我的小精灵文件并将PC设置为其精灵入口点”,则应使用QEMU的通用加载器设备,该设备在所有目标上的行为相同,并且不是-Kernel,这通常意味着“我是Linux内核,请加载我以任何随机的目标特异性,以及DO-wht-mean amean行为的组合似乎最好”。 - 如果您想加载裸机二进制而不是实际的Linux内核,则最好避免内核。
这个类似的问题,要获得Qemu 也可能会有所帮助。
Your guest code has crashed on startup, which is almost always because of problems with your exception vector table. If you use QEMU's -d options (eg -d cpu,int,guest_errors,unimp,in_asm) this will generally give a bit more detail on what exactly happened.
Looking at your ELF headers, it looks like you've not put a vector table into your binary. QEMU requires this (as does real hardware). The usual way to do this is to have a little assembly source file that lays out the data table with the addresses of the various exception entry points, though there are other ways to do this. (This is one example.)
The reason you don't see this on A-profile CPUs is that A-profile exception handling is completely different: on A-profile reset starts execution at address 0x0, and similarly exceptions are taken by setting the PC to a fixed low address. On M-profile reset works by reading the initial PC and SP values from the vector table, and exception handlers start at addresses also read from the vector table. (That is, on A-profile, the thing at the magic low addresses is code, and on M-profile, it is data, effectively function pointers).
Note also that the behaviour of the QEMU -kernel option is different between A-profile and M-profile: on A-profile it will load the ELF file into memory and honour the ELF entry point (execution will start from there). On M-profile it will load the ELF file but then start the CPU from reset in the hardware-specified manner, ie without setting PC to the ELF entry point. (This variation is essentially for historical/back-compat reasons.) If you want "just load my ELF file and set PC to its ELF entry point" you should use QEMU's generic loader device, which behaves the same way on all targets, and not -kernel, which generally means "I am a Linux kernel, please load me in whatever random target-specific plus combination of do-what-I-mean behaviour seems best". -kernel is generally best avoided if you're trying to load a bare-metal binary rather than an actual Linux kernel.
This similar question about getting a working M-profile binary running on QEMU might also be helpful.