编译ARM二进制文件,在ARMulator

时间:2016-10-04 00:49:26

标签: android arm emulation toolchain newlib

这是我的问题:

简介

我目前正在尝试在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 Armulator: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与任何二进制文件(精灵或垃圾箱)一起使用时:

  

$ ./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 *
      ======= Backtrace:=========
      /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]
      ARMulator目录下面[0x40489d]
      ARMulator目录下面[0x4022d2]
      ARMulator目录下面[0x401f3a]
      /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f0f32c9d830]
      ARMulator目录下面[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
  Unexpect Instr:

可能的原因
- ARMulator不知道如何解码某些指令。这可能就是这种情况,但我的程序看起来太基本了......它什么也没做,并且返回0 ...
- 我使用的是坏工具链,或使用正确的工具链 - 不应该以这种方式使用装甲机。

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

提前感谢您的帮助,或至少感谢您的阅读,
希望我不是唯一一个与Armulator一起度过难关的人。

问候,
约翰

1 个答案:

答案 0 :(得分:1)

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

反正。谢谢你指出这些链接,非常酷。看看最后一个Phanrahan Armulator源,我们可以看到PutWord函数中的一些特殊地址。我没有读完你的整个问题TL; DR,所以只是跳进一个简单的工作实例。

hello.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

MEMMAP:

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>
到目前为止你可能已经阅读了完整大小的重置处理程序必须是地址为零的第一个INSTRUCTION。它理想情况下是分支机构或负载PC,因为您只有一条指令可以通过异常表格。

想想gif,jpg,png等等。有各种不同的文件格式,包括像素数据以及其他信息,例如图像的宽度和高度。也许一些其他编码或压缩或其他。您可以使用文本编辑器检查.hex和.srec,它们是流行的ascii文件格式。这些只是存储程序指令和数据的不同方式。由于各种原因,有各种格式,就像图像文件有其原因,有人决定制作一个新的。 &#34; .bin&#34;在这种情况下格式不是具有该扩展名的所有文件的含义,但是当您使用-O binary与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不归属之后我会挂起来处理一个返回(如果有的话)。

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

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