2010-12-12 10 views
13

Ich arbeite an einem Assembly-Programm für einen ARM Cortex-M3-basierten Mikrocontroller (Thumb 2 Befehlssatz), mit GNU als.Wann sind GAS ELF die Anweisungen .type, .thumb, .size und .section benötigt?

In einigen Beispiel Code finde ich Direktiven wie .size, .section und .type die ich verstehe sind ELF-Richtlinien. Als Beispiel:

.section .text.Reset_Handler 
    .weak  Reset_Handler 
    .type  Reset_Handler, %function 
Reset_Handler: 
    bl  main 
    b  Infinite_Loop  
    .size Reset_Handler, .-Reset_Handler 



Die .type Richtlinie gesagt wird die Art eines Symbols eingestellt - in der Regel entweder auf% Objekt (dh Daten?) Oder% Funktion. Ich weiß nicht, welchen Unterschied es macht. Es ist nicht immer enthalten, daher bin ich unsicher, wann es verwendet werden muss.

Auch damit verbunden ist dieRichtlinie. Von dem, was ich gelesen habe es, wie es scheint, sein könnte Äquivalent:

.thumb 
.type Symbol_Name, %function 

Oder ist es etwas ganz anderes?



.size legt angeblich die Größe eines Symbols fest. Wenn das nötig ist, habe ich keine Ahnung. Wird dies standardmäßig berechnet, aber mit dieser Anweisung außer Kraft gesetzt? Wenn ja - wann möchten Sie übersteuern?



.section ist einfacher, Dokumente zu finden, und ich glaube, ich habe eine gute Vorstellung davon, was es tut , aber ich bin immer noch ein wenig unsicher über die Nutzung. So wie ich es verstehe, schaltet es zwischen verschiedenen ELF-Abschnitten um ( text für Code, data für beschreibbare Daten, bss für nicht initialisierte Daten, rodata für Konstanten und andere) und definiert neue, falls gewünscht. Ich denke, Sie würden zwischen diesen wechseln, je nachdem, ob Sie Code, Daten, nicht initialisierte Daten usw. definieren. Aber warum würden Sie einen Unterabschnitt für eine Funktion erstellen, wie im obigen Beispiel?


Jede Hilfe mit diesem wird geschätzt. Wenn Sie Links zu Tutorials oder Dokumenten finden, die dies näher erläutern - am besten verständlich für einen Anfänger -, wäre ich Ihnen sehr dankbar.

Bisher war das Using as Handbuch von etwas Hilfe - vielleicht können Sie mehr davon als ich, mit mehr Wissen.

+2

Ich habe der Frage eine Prämie hinzugefügt, in der Hoffnung, ausführlichere Antworten zu erhalten, insbesondere in Bezug auf die Anweisungen .type und .size. – Oystein

+0

Dies sollte in eine Frage pro Direktive aufgeteilt werden. Hinweis: Verstehen Sie das ELF-Format, machen Sie dann minimale Beispiele mit und ohne jede Direktive, kompilieren Sie und 'readelf -a' auf ihnen. –

Antwort

10

Ich habe Arm/Daumen seit vielen Jahren viele Assembler programmiert und habe sehr wenige der vielen Richtlinien da draußen benötigt.

.thumb_func ist ziemlich wichtig, wie von einem anderen Responder angegeben.

zum Beispiel

 
.globl _start 
_start: 
    b reset 

reset: 

.arm 

.globl one 
one: 
    add r0,r0,#1 
    bx lr 

.thumb 

.globl two 
two: 
    add r0,r0,#2 
    bx lr 

.thumb_func 
.globl three 
three: 
    add r0,r0,#3 
    bx lr 


.word two 
.word three 

.arm oder verwendet so etwas wie .code32 zu sein oder .CODE 32 sagt er dies Arm Code nicht Daumen-Code, der für die Cortex-M3 Sie nicht verwenden müssen.

.thumb ebenfalls, früher .code 16 oder vielleicht, dass immer noch funktioniert, macht gleichen Deal den folgenden Code Daumen nicht Arm.

Wenn die verwendeten Beschriftungen keine globalen Beschriftungen sind, zu denen Sie von anderen Dateien oder indirekt verzweigen müssen, benötigen Sie nicht .thumb_func. Aber damit die Adresse einer Verzweigung zu einem dieser globalen Labels richtig berechnet werden kann (lsbit ist eine 1 für den Daumen und 0 für den Arm), möchten Sie es als Daumen- oder Arm-Label markieren, und die thumb_func macht das, sonst Sie haben dieses Bit zu setzen, bevor mehr Code und das Etikett Zugabe ist nicht aufrufbaren von C.

 

00000000 <_start>: 
    0: eaffffff b 4 <one> 

00000004 <one>: 
    4: e2800001 add r0, r0, #1 
    8: e12fff1e bx lr 

0000000c <two>: 
    c: 3002  adds r0, #2 
    e: 4770  bx lr 

00000010 <three>: 
    10: 3003  adds r0, #3 
    12: 4770  bx lr 
    14: 0000000c andeq r0, r0, ip 
    18: 00000011 andeq r0, r0, r1, lsl r0 

bis .thumb der Assembler ARM-Code ist, wie gewünscht Verzweigung.

Sowohl die zwei als auch die drei Beschriftungen/Funktionen sind wie gewünscht mit einem Daumenkürzel, aber die zwei Beschriftungen haben eine geradzahlige Adresse und drei die richtige ungerade Adresse.

Die neuesten codesourcery-Tools wurden verwendet, um die obige Probe zu assemblieren, zu verknüpfen und zu entladen.

Jetzt für die Cortex-m3, wo alles Daumen (/ thumb2) thumb_func möglicherweise nicht so wichtig ist, kann es nur mit Befehlszeilenschaltern arbeiten (sehr einfach, ein Experiment zu tun, um herauszufinden). Es ist eine gute Angewohnheit, wenn Sie sich von einem Daumen-Prozessor zu einem normalen Arm/Daumen-Kern bewegen.

Assemblers fügen im Allgemeinen gerne alle diese Direktiven und andere Methoden hinzu, um Dinge wie eine Hochsprache aussehen zu lassen. Ich sage nur, dass Sie sie nicht verwenden müssen, ich habe Assemblierer für Arm ausgetauscht und viele verschiedene Assembler für viele verschiedene Prozessoren verwendet und bevorzuge den Ansatz "Weniger ist mehr", dh ich konzentriere mich auf die Baugruppe selbst und verwende so wenig werkzeugspezifische Teile wie möglich. Ich bin normalerweise die Ausnahme, nicht die Regel, so können Sie wahrscheinlich die häufiger verwendeten Direktiven herausfinden, indem Sie sich anschauen, welche Direktiven die Compiler-Ausgabe erzeugt (und mit der Dokumentation verifizieren).

 
unsigned int one (unsigned int x) 
{ 
    return(x+1); 
} 


    .arch armv5te 
    .fpu softvfp 
    .eabi_attribute 20, 1 
    .eabi_attribute 21, 1 
    .eabi_attribute 23, 3 
    .eabi_attribute 24, 1 
    .eabi_attribute 25, 1 
    .eabi_attribute 26, 2 
    .eabi_attribute 30, 2 
    .eabi_attribute 18, 4 
    .file "bob.c" 
    .text 
    .align 2 
    .global one 
    .type one, %function 
one: 
    .fnstart 
.LFB0: 
    @ args = 0, pretend = 0, frame = 0 
    @ frame_needed = 0, uses_anonymous_args = 0 
    @ link register save eliminated. 
    add r0, r0, #1 
    bx lr 
    .fnend 
    .size one, .-one 
    .ident "GCC: (Sourcery G++ Lite 2010.09-50) 4.5.1" 
    .section .note.GNU-stack,"",%progbits 

ich die .align tun verwenden, wenn Arm und Daumen Assembler oder Daten in mit Assembler Mischen, würden Sie den Assembler für eine solche Plattform erwarten etwas so offensichtlich wie Daumen Anweisungen zu wissen, auf Halbwortgrenzen und Arm Anweisungen sind an Wortgrenzen ausgerichtet. Die Werkzeuge sind nicht immer so schlau. Beregnung. Aligns über tut nicht weh

. Text ist der Standard, so dass ein wenig redundant ist, aber nicht weh tut. .text und .data sind Standardattribute (nicht spezifisch für arm), wenn Sie für eine Kombination aus rom und ram auf Ihrem Ziel kompilieren, was Ihnen egal ist (hängt davon ab, was Sie mit Ihrem Linker-Skript machen), sonst funktioniert .text für alles .

. Größe scheinbar die Größe der Funktion zu dieser Direktive starten. Der Assembler kann das nicht selbst herausfinden, also wenn die Größe dieser Funktion für Ihren Code wichtig ist, Linker-Skript, Debugger, Loader, was auch immer dann muss das richtig sein, sonst müssen Sie sich nicht darum kümmern. Eine Funktion ist ein High-Level-Konzept sowieso Assembler hat nicht wirklich Funktionen viel weniger eine Notwendigkeit, ihre Größe zu deklarieren. Und der C-Compiler ist sicherlich nicht interessiert, es ist nur auf der Suche nach einem Label zu verzweigen und im Falle der Arm-Familie ist es Daumencode oder Arm-Code, der verzweigt wird.

Sie finden die .pool-Direktive (es gibt eine neuere Entsprechung) nützlich, wenn Sie mit Ihren unmittelbaren (ldr rx, = 0x12345678) auf langen Abschnitten des Codes faul sind. Auch hier sind die Tools nicht immer schlau genug, um diese Daten nach einem unbedingten Sprung zu platzieren, haben Sie manchmal gesagt. Ich sage faule halb ernsthaft, es ist schmerzhaft, das Etikett zu machen: .word thing die ganze Zeit und ich glaube, dass sowohl die Arm- als auch die gcc-Tools für diese Abkürzung erlaubt sind, also benutze ich sie genauso wie alle anderen.

Auch llvm gibt ein zusätzliches .eabi_attribute oder zwei aus, das von der Version/mods des Code-Quelltextes zu binutils unterstützt wird, aber nicht (vielleicht noch) von den freigegebenen gnu-binutils unterstützt wird. Zwei Lösungen, die funktionieren, modifizieren llvms asm print-Funktion, um die eabi_attributes nicht zu schreiben oder sie zumindest mit einem Kommentar (@) zu schreiben, oder die binutils source/mods aus Quellcode zu holen und so binutils zu erstellen. code-Quellen neigen dazu, gnu zu führen (zum Beispiel die Unterstützung von thumb2) oder vielleicht neue Funktionen zurück zu portieren, also nehme ich an, dass diese llvm attrubutes in den mainline binutils in Kürze vorhanden sein werden. Ich habe keine negativen Auswirkungen durch Abschneiden der eabi_attributes aus dem llvm kompilierten Code erlitten.

Hier ist der Llvm-Ausgang für die gleiche Funktion oben, anscheinend ist dies die llc, die ich modifiziert habe, um die eabi_attributes auskommentieren.

 
    .syntax unified 
@ .eabi_attribute 20, 1 
@ .eabi_attribute 21, 1 
@ .eabi_attribute 23, 3 
@ .eabi_attribute 24, 1 
@ .eabi_attribute 25, 1 
@ .eabi_attribute 44, 1 
    .file "bob.bc" 
    .text 
    .globl one 
    .align 2 
    .type one,%function 
one:         @ @one 
@ BB#0:         @ %entry 
    add r0, r0, #1 
    bx lr 
.Ltmp0: 
    .size one, .Ltmp0-one 

Das Elf-Dateiformat ist gut dokumentiert und sehr einfach zu analysieren, wenn Sie wirklich sehen wollen, was die elf Einzelrichtlinien (falls vorhanden) tun. Viele dieser Direktiven sollen dem Linker mehr als alles andere helfen. .thumb_func, .text, .data zum Beispiel.

+0

Danke, das hat bestimmt geholfen. Also sollte weder .size noch .type notwendig sein, es sei denn, wir sprechen über einen speziellen Fall. – Oystein

+0

Ich habe nie .size oder .type verwendet und die meisten meiner Arbeit ist auf einem Arm und Assembler ist immer beteiligt. Ich nehme an, wenn Ihr Linker-Skript oder Loader/Elf-Parser nach solchen Dingen suchen will, dann brauchen Sie sie dort, ich benutze sehr einfache Linker-Skripte, die wirklich nur interessieren. Text vs .data, im Grunde rom vs RAM. –

+0

Über die .size-Direktive: In der android git Baum für bionic, commit fb723c87490b76d1d2fe521886f7cb6c96ed40b7 sagt: 'Update der ARM syscalls mit den BEGIN (x) und ENDE (x) Makros geben Größeninformationen für den Code der syscall. Nützlich für Valgrind –

5

Teile Ihres Programms sind eng verwandt mit dem ELF-Format, in dem die meisten Systeme (Linux, BSD, ...) ihre Objekte und ausführbaren Dateien speichern. This article sollte Ihnen einen guten Einblick darüber geben, wie ELF funktioniert, was Ihnen helfen wird, das Warum von Sektionen zu verstehen.

Einfach gesagt, Abschnitte können Sie Ihr Programm in verschiedenen Speicherbereichen organisieren, die verschiedene Eigenschaften haben, einschließlich Adresse, Berechtigung zum Ausführen und Schreiben, usw. Während der letzten Linkstufe verwendet der Linker eine bestimmte linker script, die normalerweise alle Abschnitte gruppiert des gleichen Namens zusammen (zB aller Code aus allen Kompilierungseinheiten zusammen, ...) und weist ihnen eine endgültige Adresse im Speicher zu.

Für Embedded-Systeme ist ihre Verwendung besonders offensichtlich: Erstens muss der Boot-Code (normalerweise enthalten in dem .text Abschnitt) an einer festen Adresse geladen werden, um ausgeführt zu werden. Dann können Nur-Lese-Daten in einen dedizierten Nur-Lese-Abschnitt gruppiert werden, der in den ROM-Bereich des Geräts abgebildet wird.Letztes Beispiel: Betriebssysteme haben Initialisierungsfunktionen, die nur einmal aufgerufen und danach nie wieder verwendet werden, wodurch wertvoller Speicherplatz verschwendet wird. Wenn alle diese Initialisierungsfunktionen in einem Widmungsabschnitt zusammengefasst sind, der z. B. .initcode genannt wird, und wenn dieser Abschnitt als der letzte Abschnitt des Programms eingestellt ist, kann das Betriebssystem diesen Speicher leicht wieder freigeben, wenn die Initialisierung durch Absenken des oberen beendet ist Grenze seiner eigenen Erinnerung. Linux zum Beispiel ist bekannt, dass Trick zu verwenden, und GCC können Sie auch durch postfixing es mit __attribute__ ((section ("MYSECTION")))

.type und .size sind eigentlich noch recht unklar mir eine Variable oder Methode in einem bestimmten Abschnitt zu platzieren. Ich sehe sie als Helfer für den Linker und habe sie nie außerhalb von Assembler-generiertem Code gesehen.

.thumb_func scheint nur für die alte OABI-Schnittstelle benötigt zu werden, um die Zusammenarbeit mit Arm-Code zu ermöglichen. Wenn Sie keine alte Toolchain verwenden, müssen Sie sich wahrscheinlich keine Sorgen machen.

+0

Das klärt zumindest den Abschnittsteil auf, nehme ich an. Gibt es einen besonderen Grund, eigene Bereiche zu definieren? – Oystein

+5

.thumb_func ist notwendig, wenn Sie eine Adresse der Funktion nehmen. Für eine Thumb-Funktion muss ihre Adresse das Bit 0 gesetzt haben (anders als eine Datenelementadresse). Diese Anweisung bewirkt, dass der Assembler das Symbol als solches markiert und somit weiß der Linker, wann er das Bit 0 setzen muss. –

+0

@Igor: Super! Danke – Oystein

5

Ich stieß auf diese, als ich versuchte herauszufinden, warum ARM und Thumb Interworking brach mit den letzten binutils (verifiziert mit 2.21.53 (MacPorts), auch 2.22 (Yagarto 4.7.1)).

Aus meiner Erfahrung, .thumb_func funktionierte gut mit früheren binutils, um die richtigen Interworking Veneers zu erzeugen. Bei den neueren Versionen wird jedoch die Richtlinie .type *name*, %function benötigt, um eine ordnungsgemäße Furnierbildung zu gewährleisten.

binutils mailing list post

Ich bin zu faul, eine ältere Version von binutils zu graben, bis zu überprüfen, ob die .type Richtlinie anstelle von .thumb_func für früheren binutils ausreichend ist.Ich denke, es schadet nicht, beide Direktiven in Ihren Code aufzunehmen.

Editiert: aktualisiert Kommentar über .thumb_func im Code verwenden, anscheinend funktioniert es für ARM-> Thumb Interworking zu kennzeichnen Sie die Daumen Routine Furniere zu erzeugen, aber Daumen-> ARM Netzanpassungs schlägt fehl, wenn die .type Richtlinie die ARM-Flag verwendet wird, Funktion.