Forum: Mikrocontroller und Digitale Elektronik mehrere .asm-Dateien zusammenlinken


von Ralf Handrich (Gast)


Lesenswert?

Hallo,

ich bin Anfänger in Assembler und wollte mir nun ein paar
Hilfs-funktionen schreiben, die ich dann in einer externen .asm-Datei
speichere und bei bedarf zu meinem Hauptprogramm dazulinke (ähnlich wie
in C). Kann mir jemand sagen, wie man sowas prinzipiell am Besten macht
? Mit .INCLUDE kann ich eine Datei am Anfang einfügen, aber dadurch
überschreibe ich mir meine .DEF- und .EQU-Definitionen. Kann man das
nicht irgendwie lokal regeln ?

Gruß Ralf

von Rufus T. Firefly (Gast)


Lesenswert?

Wenn Du von "linken" redest, dann müsstest Du auch den Linker
bemühen.
.INCLUDE ist nur das Äquivalent von #include, das Deklarationen, aber
eben nicht den Code einbindet.
Der Code wird vom Assembler in Objektdateien übersetzt, aus denen der
Linker dann den endgültigen ausführbaren Code erzeugt.
.INCLUDE ist erforderlich, damit ein Assemblermodul die Symbole kennt,
die in einem anderen Assemblermodul definiert sind.
C funktioniert auf exakt die gleiche Art und Weise, nur daß erstmal C
in Assembler (oder direkt in Objektcode) übersetzt wird.
Danach kommt der Linker ...

Wie das nun bei Deinem Assembler vonstatten geht, entzieht sich meiner
Kenntnist - sowas sollte im Handbuch beschrieben sein.

von Ralf Handrich (Gast)


Lesenswert?

Hallo Rufus,

erstmal Danke für die schnelle Antwort. Ich verwende den AVR-Assembler
und das AVR-Studio. Ich habe das Tutorial (hier auf der Seite)
durchgearbeitet. Wie ich aber ein Programm auf 2 Dateien aufteilen
kann, habe ich nicht gefunden. Ich lade mir mal die ASM.zip bei
atmel.com herunter - und hoffe ich finde da etwas.

Gruß Ralf

von dave (Gast)


Lesenswert?

Da der Assembler ja nicht wissen kann, ob ne "Funktion" gebraucht
wird, kann er nicht entscheiden, ober die Befehle nun mitnehmen muss
oder nicht, deswegen:
".include" ist genau das gleiche, als würde an dieser stelle die
Datei stehen..

Entsprechend überschreibst du deine .DEF und .EQUs nicht.., aber es ist
unvorteilshaft Porgrammtext ganz oben einzufügen, deswegen: Befehle erst
UNTER der INIT-Routine (oder der Routine, die durch den Reset-IRQ
angesprungen wird) anhängen, so machs ich immer.

(so siehts zumindest bei AVR aus ... bzw. so hab ichs rausgefunden
G)

dave

von dave (Gast)


Lesenswert?

Hier noch nen Beispiel:

.include "m32def.inc"
.include "header.asm"

.equ debug_mode = 0
.equ passwort_active = 0

;------------------------------
; allgemein
;------------------------------
.equ   clock       = 8000000
.equ  preload1       = (clock/256)
.equ  baudrate       = 38400
.equ   baud_wert       = clock/(16*baudrate)-1

;----------------------------------
; F L A S H
;----------------------------------
;----------------------------------
; IRQ - VECTORS
;----------------------------------
.cseg
.org 0
  rjmp init
.org 0x008
  rjmp t2_ocie2
.org 0x00e
  rjmp t1_ocie1a
;.org 0x016
;  rjmp t0_ovf

;----------------------------------
; INIT
;----------------------------------
init:
; stack pointer
  ldi temp1, LOW(RAMEND)
  out SPL, temp1
  ldi temp1, HIGH(RAMEND)
  out SPH, temp

ist natürlich gekürzt...  die m32def.inc ist klar, was es ist, und im
header sind die Register-Definitionen,die Aufteilung vom Ram und andres
.EQU.

Am Ende der Datei (nach Zeilenweise Code (meist IRQs)) gehts dann so zu
Ende:


;---------------------------------
; PC-KOMMUNIKATION
;---------------------------------
serial:
      ret


serial_out:
  sbis UCSRA,UDRE
  rjmp serial_out
  out UDR, temp1
  ret


.include "lcd.asm"
.include "menu.asm"

Und das ist dann richtiger Code... und funktionieren tuts auch noch.

dave

von Ralf Handrich (Gast)


Lesenswert?

Hallo dave,

Danke für den Tipp. Hab ich Dich richtig verstanden: die
.INCLUDE-Anweisung mit den Hilfsprogrammen erst am Ende der des
Hauptprogramms einfügen ? Ist das nicht ein bischen ... durcheinander
?

Gruß Ralf

von Ralf Handrich (Gast)


Lesenswert?

Hallo dave,

ich hab Dich richtig verstanden :). Danke nochmal für den Tipp. Bei mir
funktioniert das auch.

Gruß Ralf

von dave (Gast)


Lesenswert?

Schlag dir das mit dem Hilfsprogramm aussem Kopf..

Es ist ganz und gar nur zur Übersichtlichkeit.
Der "Text" aus der includeten Datei wir beim kompilieren einfach an
die Stelle gesetzt, wo es steht... du könntest genau so, das machen:


.include "header.asm"

.include "stackpointer.asm"
.include "timer0.asm"
.include "timer1.asm"

.include "tasterabfrage.asm"
.include "egal.was"

Oder du kannst es auch ohne jegliches include machen, doch wenn du z.b.
(wie ich) an dem Menü rumschreibst, dann haste da schon genug Zeilen und
willst nicht noch das Hauptprogramm hin-und-her scrollen.

Ich kenn mich jetzt zwar nicht bei C aus, aber da wird so ne angehängte
Datei (oder nur Header Datein?) einfach nur als Option angesehn.. Wenn
man sie aufruft, dann wird sie mitkompiliert.

dave

ps. aber solange es funktioniert G... nerver touch a running system

von Peter D. (peda)


Lesenswert?

Theoretisch kann man auch verschiedene Assemblerfiles zusammen linken,
aber praktisch macht das kaum einer.

Man muß dann nämlich noch nen Haufen Verwaltungskrams mit einfügen,
damit der Assembler verschiebbaren Code erzeugt und der Linker weiß, wo
eine Funktion anfängt, wo sie endet und welche Daten dazugehören.

Schreib einfach mal ne leere Funktion in C und lasse sie nach Assembler
übersetzen, da wird Dir schwarz vor Augen, was da für ein Wust an Text
fabriziert wird.


Deshalb assembliert man besser nur ein File und includiert die
einzelnen Unterfunktionen.

Da die Include-Reihenfolge auch die Codeplazierung bestimmt, sollte man
Unterfunktionen immer am Ende includieren bzw. frühestens nach der
Interruptvektortabelle.

Braucht man Unterfunktionen nur einmal, kann man sie auch genau an der
Stelle includieren, wo sie ausgeführt werden sollen, das spart den CALL
und das RET ein.


Peter

von Michael Melzer (Gast)


Lesenswert?

geh stimb jo goa nid

von Ralf Handrich (Gast)


Lesenswert?

Danke dave, Peter,

jetzt ist mir das schon klarer. Ich glaub ich mach das so ähnlich wie
dave in seinem Beispiel. Eine Datei für die Definitionen (ich nehm mal
an das meinst Du mit header.asm ?!), dann mein 'RJMP main', dann die
.INCLUDE "Hilfsfct.asm" und dann 'main:'. Sollte so funktionieren.

An Peter: Das mit dem 'zusammenlinken' hab ich anders gemeint. Ich
wollte nur wiederverwendbare Programmteile in eine zweite Datei
auslagen und dann einbinden (-> -INCLUDE).

Also nochmal Danke an Alle.

Gruß Ralf

von dave (Gast)


Lesenswert?

Mach die Hilfsfunktionen ans Ende von der Datei, solange sie noch mit
RCALL erreichbar sind.

Ja, header.asm da sind die Definitionen drin.

Du hasses ja verstanden ;) Wie dus jetzt machst, musste für dich selbst
finden.. und AVR-Studio zeigt auch immer schön errors an.

dave

von Rufus T. Firefly (Gast)


Lesenswert?

@Peter: Deine Herangehensweise mag bei heutigen Entwicklungssystemen die
praktikable sein, aber ich würde sie allenfalls pragmatisch nennen.

Ich habe größere Projekte in 6809-Assembler geschrieben, und das auf
Entwicklungssystemen, wo ich froh um jedes bisschen Zeitersparnis war.
Ein anständiger Assembler & Linker hat mir - zusammen mit einem
Librarymanager - da deutlich geholfen.
(Das Entwicklungssystem war an den Exorciser von Motorola angelehnt,
hatte 1 MHz Takt, 48 kByte RAM und arbeitete mit
8"-Diskettenlaufwerken, die nicht wirklich schnell waren. Das
suboptimale Dateisystem sorgte für wirklich lange Assemblierzeiten, was
den Grundstock meiner Kaffeeabhängigkeit legte)

Die pragmatische Herangehensweise ist in größeren Projekten nicht nur
aus Geschwindigkeitsgründen problematisch - werden beispielsweise
lokale Label verwendet (das sind Symbole, die nur innerhalb eines
Modules "sichtbar" sind), dann muss man beim .INCLUD(E)ieren
aufpassen, diese nicht mehrfach zu verwenden.
Möchte man fremden Code verwenden, muss man diesen vorsichtig auf darin
enthaltene Symbole überprüfen - das kann bei Objektdateien prinzipiell
einfacher sein. Die Tatsache, ob der Assembler oder der Linker eine
Fehlermeldung ausspuckt, kann ein bedeutender Hinweis sein ...

Die Arbeitsweise mit dem (relokatiblen) Assembler erscheint zunächst
aufwendiger - beim Deklarieren von Variablen sollte man nicht deren
Speicherort, sondern nur deren Namen, Größe und Linkersichtbarkeit
definieren.
Der Linker kümmert sich dann darum, alle Variablen etc. aller Module zu
organisieren.

Diese Konzepte sollten einem vertraut sein, wenn man mit C arbeitet, da
sie sich 1:1 abbilden lassen. (Ein lokales Label ist beispielsweise
äquivalent zu einer als static deklarierten Funktion).

Da im Threadtitel von linken die Rede war, erschien mir meine
Beschreibung der Vorgehensweise die naheliegendere.

von Peter D. (peda)


Lesenswert?

@Rufus,

der Geschwindigkeitsfaktor dürfte zumindest bei µCs Schnee von gestern
sein. Ein üblicher 3GHz PC ist mit Assemblieren fertig, da hat man die
Maustaste kaum wieder losgelassen.


Und größere Programme macht man besser in C und nicht in Assembler.

Aber auch bei der C-Programmierung habe ich mit einem Objektfile
angefangen und includiert. Erst viel später habe ich größere Programme
wirklich in mehrere C-Files unterteilt.

Allerdings machen es einem die Windows-IDEs etwas schwer, man muß jedes
File manuell dem Build hinzufügen.

Deshalb bevorzuge ich das Compilieren im DOS-Fenster, da nehme ich eine
Batch, die vollautomatisch alle *.C-Files im Verzeichnis zusammen
linkt.

Auch wenn dabei immer sämtliche Sourcen neu compiliert werden, stellt
das keinen erwähnenswerten Zeitfaktor dar.


Peter

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.