【问题标题】:Compile ARM binaries, run them in ARMulator编译 ARM 二进制文件,在 ARMulator 中运行它们
【发布时间】:2016-10-04 00:49:26
【问题描述】:

这是我的问题:

简介

我目前正在尝试在 ARM 处理器上执行一些基本代码。由于我目前(可能很长一段时间)周围没有任何 ARM 硬件,所以我已经使用 QEMU(一个 ARM 仿真器)有几天了,我不得不说,它就像一个魅力.但是使用 QEMU,我感觉就像拔剑杀苍蝇一样。于是找了一些轻量级的模拟器,发现了ARMulator。

“ARMulator 是一系列程序,可模拟各种 ARM 处理器及其支持架构的指令集。 ARMulator 透明地连接到兼容的 ARM 调试器,以提供独立于硬件的 ARM 软件开发环境。通过远程调试接口 (RDI) 进行通信。”
(来源:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0032f/index.html
“准确度很好,虽然它被归类为周期计数准确而不是周期准确,这是因为 ARM 流水线没有完全建模(尽管寄存器互锁是)。解决方案是针对一条指令,因此当单步执行时,寄存器互锁被忽略,并且返回的循环计数与程序仅运行时不同,这是不可避免的。”
(来源:https://en.wikipedia.org/wiki/ARMulator

环境

从那里,我尝试了几个 ARMulator 版本。不得不说周围没有很多,事实上我只尝试了3个版本(名字不是官方的,那只是我给他们起的名字):
- XYZ 机械臂:https://github.com/x-y-z/armulator 2016-02-20
- SourceForge Armulator : https://sourceforge.net/projects/armulator/ 2013-04-26
- Phanrahan Armulator : https://github.com/phanrahan/armulator 2014-11-11

我不确定这些版本是不是官方版本,我想我已经在不同的网站上多次看到有一些版本是真正官方的,可能是专有版本,并且包含的​​工具超出了所需的工具。以下是我所说的一些例子:
- 在 ARM Connected Community 上,他们谈论了一个 RealViewDevelopmentSuite,它似乎包含 ARMulator:https://community.arm.com/message/12272#12272
- ......当我再次找到其中一个时会添加其他人 但这些解决方案不是免费的。

现在关于工具链。我发现的资源中有两种不同的工具链:
- arm-elf-abi :在 XYZ ARMulator GitHub 上说明,建议使用此命令 ($ arm-elf-gcc -mthumb -Bstatic -o ) 编译二进制可执行文件。
我找到的唯一版本是适用于 Windows 的……遗憾的是,我找不到适用于 Unix 的版本。
- Arm-none-eabi :在本教程中说明:http://www.bravegnu.org/gnu-eprog/hello-arm.html,这是我一直在使用 QEMU 的那个。我在某处读到过在编译 ARM 程序集时不需要 Arm-elf 工具链,而 Arm-none 对于这种情况就足够了。

我测试的两个程序尽可能地简单:

组装中的一个:helloarm.s

  .global _start
 .text  
entry:  b _start  
  .align  
_start: 
  mov   r4, #5         @ Load register r4 with the value 5
  mov   r3, #4         @ Load register r3 with the value 4
  add   r0, r4, r3     @ Add r3 and r4 and store in r0
  b stop
stop:  b stop @  Infinite loop

C 中的一个:test.c

int c_entry() {
  return 0;
}

编译过程

起初,我使用了与本教程中解释的 QEMU 相同的方法:http://www.bravegnu.org/gnu-eprog/hello-arm.html。在 QEMU 上,一切正常,但仿真过程略有不同。在执行 QEMU 之前,我必须先将二进制文件加载到 RAM 中。 启动 ARMulator ($ armulator ) 的方式不同,我想二进制自动加载的是 RAM。

我尝试了三种不同的编译方式,不知道哪种最合适。这里是:

组装:

 $ arm-none-eabi-as –s -g helloarm.s -o helloarm.o    
 $ arm-none-eabi-ld -Ttext=0x0 -o helloarm.elf helloarm.o    
 $ arm-none-eabi-objcopy -O binary helloarm.elf helloarm.bin      

我们现在应该有两个“二进制文件”,一个 .bin 和一个 .elf。
我仍然不知道有什么区别。需要多读一些。

C:

 $ arm-none-eabi-gcc -mthumb -Bstatic --specs=nosys.specs srcs/main.c –o a.out  

一个额外的:
我还尝试了本教程中解释的以下方法,这让我觉得 Armulator 是用来执行 .elf 二进制文件的。使用此方法创建的文件称为 c_entry。
https://balau82.wordpress.com/2010/02/14/simplest-bare-metal-program-for-arm/ 问题是一样的。

从那时起,我们有 6 个二进制文件:

  • helloarm.bin
  • helloarm.elf

  • main.elf

  • a.out

  • c_entry.bin

  • c_entry.elf

问题

将 SourceForge 和 Phanrahan Armulator 与任何二进制文件(elf 或 bin)一起使用时:

$ ./armulator asm-helloarm.bin
打开文件 00000000.bin 时出错
$ ./armulator a.out
打开文件 00000000.bin 时出错
$ ./armulator helloarm.elf
打开文件00000000.bin时出错

使用 XYZ Armulator 时:

  • 使用 helloarm.elf 二进制文件或任何 .elf 文件:

    $ armulator helloarm.elf

    错误:代码段外:0x24
    * `armulator' 中的错误:双重释放或损坏(顶部):0x0000000001000550 *
    ======= 回溯:=========
    /lib/x86_64-linux-gnu/libc.so.6(+0x77725)[0x7f0f32cf4725]
    /lib/x86_64-linux-gnu/libc.so.6(+0x7ff4a)[0x7f0f32cfcf4a]
    /lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f0f32d00abc]
    机械臂[0x40489d]
    机械臂[0x4022d2]
    机械臂[0x401f3a]
    /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f0f32c9d830]
    机械臂[0x402109]
    ======= 内存映射:========
    00400000-0040e000 r-xp 00000000 08:01 3802861 /usr/local/bin/armulator
    0060d000-0060e000 r--p 0000d000 08:01 3802861 /usr/local/bin/armulator
    0060e000-0060f000 rw-p 0000e000 08:01 3802861 /usr/local/bin/armulator
    00fe4000-01016000 rw-p 00000000 00:00 0 [堆]
    7f0f2c000000-7f0f2c021000 rw-p 00000000 00:00 0
    7f0f2c021000-7f0f30000000 ---p 00000000 00:00 0
    7f0f32974000-7f0f32a7c000 r-xp 00000000 08:01 3281469 /lib/x86_64-linux-gnu/libm-2.23.so
    7f0f32a7c000-7f0f32c7b000 ---p 00108000 08:01 3281469 /lib/x86_64-linux-gnu/libm-2.23.so
    7f0f32c7b000-7f0f32c7c000 r--p 00107000 08:01 3281469 /lib/x86_64-linux-gnu/libm-2.23.so
    7f0f32c7c000-7f0f32c7d000 rw-p 00108000 08:01 3281469 /lib/x86_64-linux-gnu/libm-2.23.so
    7f0f32c7d000-7f0f32e3d000 r-xp 00000000 08:01 3281399 /lib/x86_64-linux-gnu/libc-2.23.so
    7f0f32e3d000-7f0f3303c000 ---p 001c0000 08:01 3281399 /lib/x86_64-linux-gnu/libc-2.23.so
    7f0f3303c000-7f0f33040000 r--p 001bf000 08:01 3281399 /lib/x86_64-linux-gnu/libc-2.23.so
    7f0f33040000-7f0f33042000 rw-p 001c3000 08:01 3281399 /lib/x86_64-linux-gnu/libc-2.23.so
    7f0f33042000-7f0f33046000 rw-p 00000000 00:00 0
    7f0f33046000-7f0f3305c000 r-xp 00000000 08:01 3281437 /lib/x86_64-linux-gnu/libgcc_s.so.1
    7f0f3305c000-7f0f3325b000 ---p 00016000 08:01 3281437 /lib/x86_64-linux-gnu/libgcc_s.so.1
    7f0f3325b000-7f0f3325c000 rw-p 00015000 08:01 3281437 /lib/x86_64-linux-gnu/libgcc_s.so.1
    7f0f3325c000-7f0f333ce000 r-xp 00000000 08:01 3672061 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
    7f0f333ce000-7f0f335ce000 ---p 00172000 08:01 3672061 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
    7f0f335ce000-7f0f335d8000 r--p 00172000 08:01 3672061 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
    7f0f335d8000-7f0f335da000 rw-p 0017c000 08:01 3672061 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
    7f0f335da000-7f0f335de000 rw-p 00000000 00:00 0
    7f0f335de000-7f0f33604000 r-xp 00000000 08:01 3281371 /lib/x86_64-linux-gnu/ld-2.23.so
    7f0f337e1000-7f0f337e6000 rw-p 00000000 00:00 0
    7f0f33800000-7f0f33803000 rw-p 00000000 00:00 0
    7f0f33803000-7f0f33804000 r--p 00025000 08:01 3281371 /lib/x86_64-linux-gnu/ld-2.23.so
    7f0f33804000-7f0f33805000 rw-p 00026000 08:01 3281371 /lib/x86_64-linux-gnu/ld-2.23.so
    7f0f33805000-7f0f33806000 rw-p 00000000 00:00 0
    7ffc24c19000-7ffc24c3a000 rw-p 00000000 00:00 0 [堆栈]
    7ffc24ca4000-7ffc24ca6000 r--p 00000000 00:00 0 [vvar]
    7ffc24ca6000-7ffc24ca8000 r-xp 00000000 00:00 0 [vdso]
    ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
    中止(核心转储)

  • 使用 helloarm.bin 二进制文件:

$ armulator helloarm.bin
分段错误(核心转储)

  • 使用 GCC 编译的 C 二进制文件:

$ armulator a.out
意外指令:

可能的原因
- ARMulator 不知道如何解码某些指令。可能是这样,但我的程序似乎太基础了……它什么也不做,返回 0……
- 我使用了错误的工具链,或者错误地使用了正确的工具链。
- 不应以这种方式使用 Armulator。

注意事项
使用 arm-none-eabi-gdb 运行二进制文件时,我无法运行或启动程序。 只有这个命令有效:target,但它只会将目标文件重置为已选择的二进制文件。
当我键入 start 时,它显示“未加载符号表。使用“文件”命令。”

提前感谢您的帮助,或者至少感谢您的阅读,
希望我不是唯一一个在 Armulator 上遇到困难的人。

问候,
约翰

【问题讨论】:

  • “我目前没有任何 ARM 硬件” 你没有手机吗?几乎所有这些都是基于 ARM 的。
  • 你好 Michael,我有一部 Android 手机,但我更愿意完全控制执行我的程序的机器。我想计算周期,衡量性能,以及为什么不修改一些模拟器源代码以更好地理解幕后发生的事情。谢谢你的建议,但这不是我想要的。

标签: android arm emulation toolchain newlib


【解决方案1】:

我认为重点是您对没有 ARM 的评论。具有某种开/关开关的东西的比例很高。有一个手臂。如果您有一台 x86 计算机来阅读此网页,那台计算机中可能有多个 ARMS 以及一些其他处理器。

无论如何。感谢您指出这些链接,非常酷。查看最后一个 Phanrahan Armulator 源码,我们可以在 PutWord 函数中看到一些特殊地址。我没有阅读您的整个问题 TL;DR,所以只是跳入一个简单的工作示例。

你好.s:

.globl _start
_start:
    b reset
    b hang
    b hang
    b hang
    b hang
    b hang
    b hang
    b hang

hang: b hang

reset:
    mov r0,#0x16000000
    mov r1,#0x55
    str r1,[r0]
    add r1,r1,#1
    str r1,[r0]
    mov r0,#0xF0000000
    str r1,[r0]
    b hang

内存映射:

MEMORY
{
    ram : ORIGIN = 0x00000000, LENGTH = 0x1000
}
SECTIONS
{
    .text : { *(.text*) } > ram
}

生成文件:

#ARMGNU ?= arm-none-linux-gnueabi
ARMGNU ?= arm-none-eabi
#ARMGNU ?= arm-linux-gnueabi
COPS = -Wall -O2 -nostdlib -nostartfiles -ffreestanding 


all : hello.bin

clean :
    rm -f *.o
    rm -f *.bin
    rm -f *.elf
    rm -f *.list
    rm -f *.srec
    rm -f *.hex

hello.o : hello.s
    $(ARMGNU)-as hello.s -o hello.o


hello.bin : hello.o memmap
    $(ARMGNU)-ld -T memmap hello.o -o hello.elf
    $(ARMGNU)-objdump -D hello.elf > hello.list
    $(ARMGNU)-objcopy hello.elf -O ihex hello.hex
    $(ARMGNU)-objcopy hello.elf -O srec hello.srec 
    $(ARMGNU)-objcopy hello.elf -O binary hello.bin 

正如错误消息所暗示的那样,一旦将 hello.bin 复制到 00000000.bin。

然后

./armulator

r0 = 16000000
r1 = 00000055
Ur1 = 00000056
Vr0 = f0000000

ERROR PutWord(0xF0000000,0x56)
NumScycles 8
NumNcycles 7
NumIcycles 0
NumCcycles 0
NumFcycles 0
NumInstrs  8
TotlCycles 15

我们看到出现了 U 和 V 字符(0x55 和 0x56)以及其他特殊地址的反应。

hello.list

00000000 <_start>:
   0:   ea000007    b   24 <reset>
   4:   ea000005    b   20 <hang>
   8:   ea000004    b   20 <hang>
   c:   ea000003    b   20 <hang>
  10:   ea000002    b   20 <hang>
  14:   ea000001    b   20 <hang>
  18:   ea000000    b   20 <hang>
  1c:   eaffffff    b   20 <hang>

00000020 <hang>:
  20:   eafffffe    b   20 <hang>

00000024 <reset>:
  24:   e3a00416    mov r0, #369098752  ; 0x16000000
  28:   e3a01055    mov r1, #85 ; 0x55
  2c:   e5801000    str r1, [r0]
  30:   e2811001    add r1, r1, #1
  34:   e5801000    str r1, [r0]
  38:   e3a0020f    mov r0, #-268435456 ; 0xf0000000
  3c:   e5801000    str r1, [r0]
  40:   eafffff6    b   20 <hang>

到目前为止,您可能已经阅读了完整尺寸的重置处理程序必须是地址零处的第一个指令。理想情况下,它是分支或加载 pc,因为您只有一条指令可以退出/越过异常表。

bin、hex、elf 等。想想 gif、jpg、png 等。各种不同的文件格式既有像素数据,也有其他信息,例如图像的像素宽度和高度。也许其他一些编码或压缩或其他。您可以使用文本编辑器检查 .hex 和 .srec,它们是流行的 ascii 文件格式。这些中的每一个都只是为我们的程序存储指令和数据的不同方式。由于各种原因,有各种格式,就像图像文件有他们决定制作新格式的原因一样。在这种情况下,“.bin”格式并不是所有具有该扩展名的文件的含义,但是当您将 -O 二进制文件与 objcopy 一起使用时,您会得到一个原始内存映像

hexdump -C hello.bin 
00000000  07 00 00 ea 05 00 00 ea  04 00 00 ea 03 00 00 ea  |................|
00000010  02 00 00 ea 01 00 00 ea  00 00 00 ea ff ff ff ea  |................|
00000020  fe ff ff ea 16 04 a0 e3  55 10 a0 e3 00 10 80 e5  |........U.......|
00000030  01 10 81 e2 00 10 80 e5  0f 02 a0 e3 00 10 80 e5  |................|
00000040  f6 ff ff ea                                       |....|
00000044

将其与上面的列表进行比较,您会发现这只是原始指令/程序数据。这显然是这个模拟器想要的。

如果你想将它扩展到 C 程序中,你至少需要设置一个堆栈(例如 mov sp,#0x4000)然后分支链接到入口点的名称,不必是 main()有时你不想要 main() 因为一些编译器会添加额外的垃圾。然后在我的情况下,在 bl 到 notmain 之后我 b 挂起以处理返回(如果有的话)。

您想在我的 makefile 中使用所有这些 COPS 标志。

我编写裸机的方式是我可以使用 gcc 编译器 arm-none-eabi、arm-none-linux-gnueabi 等的任何变体。这些差异应该与包含或支持的 C 库有关。在这些情况下,正常的 glibc 与 newlib。我不调用 C 库函数,所以我在那里没有问题,我只需要一个原始编译器来从 C 到对象。链接描述文件可以像我展示的那样简单,您可以根据需要添加 .data 和 .bss。如果您觉得有必要,它们可能会变得更加复杂。如果您没有在链接器脚本中调用对象,那么链接器会以命令行顺序使用这些对象,因此您的条目对象(开头带有异常表的那个)必须在对象列表中排在第一位。

【讨论】:

    猜你喜欢
    • 2018-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-08
    • 2016-04-08
    • 1970-01-01
    • 2011-10-08
    • 2021-03-22
    相关资源
    最近更新 更多