2016-10-04 1 views
2

Voici mon problème:binaires ARM Compile, les exécuter dans ARMulator

Présentation

J'essaie actuellement d'exécuter un code de base sur un processeur ARM. Comme actuellement (et probablement depuis longtemps) je n'ai pas de matériel ARM autour de moi, j'utilise QEMU (un émulateur ARM) depuis quelques jours, ce qui, je dois le dire, fonctionne comme un charme . Mais en utilisant QEMU, j'ai envie de dessiner mon épée pour tuer une mouche. J'ai donc cherché des émulateurs plus légers et j'ai découvert ARMulator. «L'ARMulator est une famille de programmes qui émule les jeux d'instructions de divers processeurs ARM et leurs architectures de support. L'ARMulator est connecté de manière transparente à des débogueurs ARM compatibles pour fournir un environnement de développement de logiciel ARM indépendant du matériel. La communication s'effectue via l'interface de débogage à distance (RDI). "
(Source: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0032f/index.html)
" La précision est bonne, même si elle est considérée comme un nombre de cycles précis plutôt que comme un cycle précis, car le pipeline ARM n'est pas entièrement modélisé (bien que les verrouillages de registre soient). La résolution est à une instruction, en conséquence lorsque le pas à pas les verrouillages de registre sont ignorés et différents chefs de cycle sont renvoyés que si le programme avait simplement courir, cela était inévitable «
(Source: https://en.wikipedia.org/wiki/ARMulator).

Environnement De là, j'ai essayé plusieurs versions d'ARMulator. Je dois dire qu'il n'y en a pas beaucoup, en fait j'ai seulement essayé 3 versions (les noms ne sont pas officiels, c'est simplement un nom que je leur ai donné pour les reconnaître):
- 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

Je ne suis pas sûr que ces versions sont officielles, et je pense que je l'ai vu à plusieurs reprises sur des sites différents, il a été certaines versions vraiment officielles, probablement propriétaires et incluant plus que les outils nécessaires. Voici quelques exemples de ce que je parle:
- ARM Connected Community, ils parlent d'un RealViewDevelopmentSuite, qui semble contenir ARMulator: https://community.arm.com/message/12272#12272
- ... Ajoutera autres quand je trouve l'un d'eux à nouveau Mais ces solutions sont pas libre.

Maintenant à propos de la chaîne d'outils. Deux chaînes d'outils différentes sont indiquées dans les ressources que j'ai trouvées:
- Arm-elf-abi: indiqué sur le GitHub XYZ ARMulator, il est recommandé d'utiliser cette commande ($ arm-elf-gcc -mthumb -Bstatic -o) compiler l'exécutable binaire.
La seule version que j'ai trouvé était pour Windows ... malheureusement, je ne pouvais pas en trouver pour Unix.
- Arm-none-eabi: indiqué sur ce tutoriel: http://www.bravegnu.org/gnu-eprog/hello-arm.html, c'est celui que j'ai utilisé avec QEMU. J'ai lu quelque part que la chaîne d'outils Arm-elf n'était pas nécessaire lors de la compilation de l'assemblage ARM, et Arm-none était suffisant pour ce cas.

Les deux programmes que j'ai testé ont été faits pour être la plus simple possible:

une à l'Assemblée: 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 

Un C: test.c

int c_entry() { 
    return 0; 
} 

processus de compilation

Au début, j'utilisé la même manière qui a travaillé sur QEMU a expliqué dans ce tutoriel: http://www.bravegnu.org/gnu-eprog/hello-arm.html. Sur QEMU, tout a bien fonctionné, mais le processus d'émulation est légèrement différent. J'ai dû charger le binaire dans la RAM avant d'exécuter QEMU. La façon de lancer ARMulator ($ armulator) étant différente, je suppose que le binaire est automatiquement chargé est la RAM.

J'ai essayé trois différentes façons de compiler, pas sûr de ce qui est le plus approprié one.Here est:

Assemblée:

$ 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  

Nous devrions avoir maintenant deux « binaires », les. bin un et le .elf un.
Je ne sais toujours pas quelle est la différence. Besoin de lire un peu plus.

C:

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

Un supplément un:
J'ai aussi essayé la méthode suivante a expliqué dans ce tutoriel, qui m'a fait penser ARMulator a été fait pour exécuter les binaires .elf. Les fichiers créés avec cette méthode s'appellent c_entry.
https://balau82.wordpress.com/2010/02/14/simplest-bare-metal-program-for-arm/ Les problèmes sont les mêmes.

A partir de là, nous avons 6 binaires:

  • helloarm.bin
  • helloarm.elf

  • main.elf

  • a.out

  • c_entry .bin

  • c_entry.elf

Questions

Lorsque vous utilisez SourceForge et Phanrahan ARMulator avec un fichier binaire (elfe ou bin):

$ ./armulator asm-helloarm.bin
Error opening file 00000000.bin
$ ./armulator a.out
Error opening file 00000000.bin
$ ./armulator helloarm.elf
Error opening file 00000000.bin

Lorsque vous utilisez XYZ ARMulator:

  • Avec helloarm.elf binaire, ou tout .elf fichier:

    $ ARMulator helloarm.elf

    Error:Out of Code Segment:0x24
    * Error in `armulator': double free or corruption (top): 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]
    ======= Memory map: ========
    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 [heap]
    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 [stack]
    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]
    Aborted (core dumped)

  • Avec helloarm.bin binaire:

$ armulator helloarm.bin
Segmentation fault (core dumped)

  • Avec GCC-binaire compilé C:

$ armulator a.out
Unexpect Instr:

Causes possibles
- ARMulator ne sait pas comment décoder des instructions. C'est probablement le cas, mais mon programme semble trop basique pour être le cas ... Il ne fait rien, et renvoie 0 ...
- J'utilise une mauvaise chaîne d'outils, ou j'utilise mal la chaîne d'outils correcte.
- L'armateur ne doit pas être utilisé de cette façon.

NOTES
Lors de l'exécution des binaires avec bras-none-eabi-gdb, je ne peux pas courir ou lancer le programme. Seule cette commande fonctionne: target, mais elle ne réinitialise que le fichier cible au binaire déjà choisi.
Lorsque je tape start, il est indiqué "Aucune table de symboles chargée. Utilisez la commande "fichier". "

Merci d'avance pour votre aide, ou au moins merci pour la lecture,
En espérant que je ne suis pas le seul qui a eu du mal avec Armulator.

Cordialement,
John

+0

_ "Je n'ai actuellement aucun matériel ARM autour de moi" _ Vous n'avez pas de téléphone portable? Presque tous sont basés sur ARM. – Michael

+0

Bonjour Michael, j'ai un téléphone Android mais je préfère avoir un contrôle total sur la machine qui exécute mes programmes. Je voudrais compter les cycles, mesurer les performances, et pourquoi ne pas modifier une partie du code source de l'émulateur pour mieux comprendre ce qui se passe dans les coulisses. Merci pour votre suggestion, mais ce n'est pas ce que je veux. – IceTea

Répondre

1

Je pense que le point est votre commentaire de ne pas avoir un ARM. Un pourcentage élevé de choses qui ont une sorte de commutateur marche/arrêt. Avoir un bras. Si vous avez un ordinateur x86 pour lire cette page Web, cet ordinateur a probablement plusieurs ARMS ainsi qu'un certain nombre d'autres processeurs.

Quoi qu'il en soit. Merci d'avoir signalé ces liens, très cool. En regardant la dernière source de Phanrahan Armulator, nous pouvons voir quelques adresses spéciales dans la fonction PutWord. Je n'ai pas lu toute votre question TL; DR, donc je vais juste sauter dans un exemple de travail simple.

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 
} 

Makefile:

#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 

Une fois construit le hello.bin copie à 00000000.bin comme le message d'erreur Implique .

puis

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

nous voyons les caractères U et V sortent (0x55 et 0x56) ainsi que les autres adresses spéciales réagir.

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> 

que vous avez pu lire jusqu'à présent pour une taille complète le gestionnaire de réinitialisation doit être la première instruction à l'adresse zéro.Et c'est, idéalement soit une branche ou un pc de chargement puisque vous n'avez qu'une seule instruction à sortir/sur la table d'exception. Bin, hex, elf, etc. Pensez à gif, jpg, png, etc. Différents formats de fichiers qui ont à la fois des données de pixels et d'autres informations comme le nombre de pixels de l'image. Peut-être d'autres encodages ou compressions ou autre. Vous pouvez examiner les fichiers .hex et .srec avec un éditeur de texte, ils sont populaires formats de fichiers ASCII. Chacun d'entre eux est juste une façon différente de stocker les instructions et les données pour notre programme. Pour diverses raisons, il existe différents formats, tout comme les fichiers d'image ont leurs raisons pour lesquelles quelqu'un a décidé d'en faire un nouveau. le format « .bin » dans ce cas, ce qui est pas ce que tous les fichiers avec cette extension moyenne, mais lorsque vous utilisez binaire -O avec objcopy vous obtenez une image mémoire brute

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 

et en le comparant à la liste ci-dessus vous voyez ceci est juste l'instruction brute/les données de programme. Ce qui est apparemment ce que veut cet émulateur. Si vous voulez étendre cela en programmes C, vous devez au minimum configurer une pile (mov sp, # 0x4000 par exemple), puis relier le lien au nom du point d'entrée, ne doit pas nécessairement être principal () et parfois vous ne voulez pas main() car certains compilateurs ajoutent des ordures supplémentaires. puis dans mon cas après le bl à notmain je b à suspendre pour gérer un retour s'il y en a un.

Vous souhaitez utiliser tous ces indicateurs COPS dans mon fichier makefile.

Comme ils écrivent mon baremetal, je peux utiliser n'importe laquelle des variantes des compilateurs gcc arm-none-eabi, arm-none-linux-gnueabi, et ainsi de suite. Les différences sont censées avoir à voir avec la bibliothèque C incluse ou supportée. La glibc normale vs newlib dans ces cas. Je n'appelle pas les fonctions de la bibliothèque C, donc je n'ai pas de problème là-bas, j'ai juste besoin d'un compilateur brut pour passer de C à l'objet. Le script de l'éditeur de liens peut être aussi simple que je l'ai montré, vous pouvez ajouter .data et .bss au besoin. Ils peuvent être beaucoup plus compliqués si vous en ressentez le besoin. Si vous n'invoquez pas d'objets dans le script de l'éditeur de liens, l'éditeur de liens utilise les objets dans l'ordre de la ligne de commande pour que votre objet d'entrée (celui avec la table d'exceptions au début) soit en premier dans la liste des objets.