Forum: Mikrocontroller und Digitale Elektronik Frage zu Gnu Assembler


von Jan (Gast)


Lesenswert?

Hallo.

Da ich jetzt vermehrt versuche, strukturiert mit Libs zu arbeiten und 
deshalb auch Libs erstelle, habe ich das Problem, dass ich bei einem 
#include "lib.S" die komplette Lib mitnehme, auch wenn ich daraus nur 
einzelne Funktionen brauche.

Gibt es irgendwie einen Trick, mit dem ich mit Conditionals Blöcke 
hinzufügen kann? Nach dem Motto

.ifcalled some_function
some_function:
code
.endif

C macht das ja bereits so. Wäre halt schön, wenn man das dem Assembler 
auch beibringen könnte.

von Georg A. (georga)


Lesenswert?

Jede Funktion in eine eigene Section und dem Linker --gc-sections sagen?

von Jan (Gast)


Lesenswert?

Hmmm habe ich grad mal ausprobiert.
"0 Bytes Flash used" :D
Der hat mal eben alles weggekürzt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Jan schrieb:
> #include "lib.S" die komplette Lib

Das ist keine "Lib" dann.

Eine Library ist eine Sammlung von Objektmoduln, die man dem Linker mit 
auf die Reise gibt, auf dass er aus ihr undefinierte globale 
Symbolreferenzen auflösen kann. Das macht er, indem er jeweils einen 
Modul (also ein .o file) rausnimmt und danach schaut, ob er aus der 
gleichen Library weitere (ggf. auch durch den aktuellen Modul neu hinzu 
gekommene) Referenzen befriedigen kann. Wenn das nichts mehr bringt, 
geht er zur nächsten Library.

Ob die Objektmodule nun aus Assemblerdateien oder aus C-Quellen oder aus 
FORTRAN-Quellen kamen, ist dem Linker egal.

Ergo: alles, was sowieso immer gemeinsam gebraucht wird, kann in eine 
Quelldatei gehen und damit in einen Objektmodul übersetzt werden. 
(Klassiker: malloc und free) Alles, was voneinander logisch unabhängig 
ist, gehört in verschiedene Quelldateien und wird zu verschiedenen 
Objektmodulen übersetzt.

Alle diese Objektmodule werden dann mit dem Librarian zu einer 
Bibliothek verknotet (Dateiendung .a). Die übliche Konvention ist, diese 
lib<irgendwas>.a zu benennen, damit kann man dem Linker dann die Option 
-l<irgendwas> mitgeben, und er sucht sie unter diesem genannten Namen. 
Aber man kann auch lib<irgendwas>.a an der gleichen Stelle der 
Linker-Kommandozeile angeben, das bleibt sich gleich.

Natürlich hat es keinen Sinn, dem Linker ausschließlich Bibliotheken mit 
auf die Reise zu geben. Er hat ja initial kein einziges undefiniertes 
globales Symbol, folglich muss er aus keiner einzigen Bibliothek 
irgendwas entnehmen – und ist gleich wieder fertig mit der Arbeit. Man 
kann sich mit der Linkeroption -u behelfen, um zwangsweise ein 
undefiniertes Symbol von Anfang an zu erzwingen, aber sinnvoller ist es 
natürlich, irgendwas auf der Kommandozeile vor den Libraries zu haben, 
was dann tatsächlich Dinge aus der Lib benötigt, die sich der Linker 
reinziehen muss.

von Jan (Gast)


Lesenswert?

Danke Jörg. Ich habe offensichtlich nicht verstanden, wie man das mit 
den Libs richtig macht. Gibt es dazu irgendwo ein gutes Tutorial, ohne 
dass man zig Stunden investieren muss, um die gcc internals zu 
verstehen?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Naja, das hat mit GCC gar nicht so viel zu tun, das ist klassisches 
(Unix-)Library- und Linker-Handling.

Nein, Tutorial kenne ich auch nicht, aber sollte sich im Netz finden 
lassen.

von Jan (Gast)


Lesenswert?

Da ich gerade noch andere Möglichkeiten untersuche.... gibt es eine 
einfache Lösung für folgendes Problem?
1
.ifdef require_some_code
2
some_code:
3
...
4
.endif
5
6
....
7
8
.ifdef require_some_other_code
9
require_some_code = 1
10
some_other_code:
11
...
12
call some_code
13
.endif

ERROR: undefined reference to some_code

Er müsste also weiter oben merken, dass der Code weiter unten benötigt 
wird. Anders gesagt müsste es eine Möglichkeit geben, irgendwas zu 
definieren, was  global gültig wäre. Da es 1001 Möglichkeiten gibt, was 
zu definieren, wollte ich mal fragen, ob da jemand was kennt.

: Bearbeitet durch Moderator
von Thomas Z. (usbman)


Lesenswert?

eine Möglichkeit wäre natürlich einzelne Funktionen so zu schreiben, 
dass diese als getennte Dateien übsetzt werden können. Dazu musst du 
dich dann mit public und extern auseinandersetzen.
Beim linken gibst du dann einfach die .o Dateien mit die du brauchst.

Das hat auch nix mit GNU, GCC oder linux zu tun, so arbeitet eigendlich 
jeder Assembler oder Compiler. Ok die ganz primitiven Teile mal ausen 
vor.

Das ist im Prinzip die Vorstufe zu richtigen libs wie es Jörg ja schon 
ausführlich beschrieben hat.
Das ist zu Anfang zwar etwas mer Aufwand bis du den Dreh raus hast. 
Danach wird dir aber vieles in verrschieden toolchains klarer.

Als Literatur könnte ich dir z.B die alten Handbücher zum alten Borland 
Turbo Assembler empfehlen, die sind wirklich gut gemacht. Must halt die 
Sachen mit der Segmentierung ignorieren. Die Handbücher sollten sich in 
einer Archiv Bibliotek finden lassen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

#ifdef oder .ifdef sind für Bibliotheken eher kontraproduktiv. Sie 
wirken zur Übersetzungszeit, aber die Idee einer Bibliothek ist es ja 
gerade, dass sie nicht jedesmal neu übersetzt wird (egal ob compiliert 
oder assembliert), sondern dass sie vorab übersetzte Objektmodule 
beinhaltet, die bei Bedarf mit dazu gelinkt werden.

von Jan (Gast)


Lesenswert?

Jörg W. schrieb:
> aber die Idee einer Bibliothek ist es ja
> gerade, dass sie nicht jedesmal neu übersetzt wird

Wie soll das denn gehen? In den Libs verwende ich Befehle wie cbi und 
sbi, die via Konstanten auf die richtigen Ports/Pins zugreifen. Da bei 
jedem Projekt dort andere Zahlen reingehören, muss die Lib doch eh immer 
neu übersetzt werden.

Auf Software-Layer, wo immer alle Gegebenheiten identisch sind, mag das 
ja funktionieren, aber auf Hardware-Ebene sehe ich da keine Chance.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Jan schrieb:
> Jörg W. schrieb:
>> aber die Idee einer Bibliothek ist es ja
>> gerade, dass sie nicht jedesmal neu übersetzt wird
>
> Wie soll das denn gehen?

Indem man sie vorab compiliert / assembliert, so wie man das schon seit 
50 Jahren macht. ;-)

> In den Libs verwende ich Befehle wie cbi und
> sbi, die via Konstanten auf die richtigen Ports/Pins zugreifen.

Das kannst du in einer (echten) Bibliothek halt nicht tun. Wenn du das 
unbedingt als Bibliothek machen willst und IO-Zugriffe benutzen, dann 
geht das nur über die zugehörigen Speicheradressen (die ja jeder IO-Port 
beim AVR ohnehin besitzt).

Andere Architekturen (wenn du in der AVR-Linie bleibst, bereits beim 
Xmega) sind in der Hinsicht entwas einfacher zu handhaben, da dort 
üblicherweise jedes Peripheral über eine struct angesprochen wird für 
die einzelnen Steuerregister, wobei die verschiedenen Instanzen jeweils 
auf eigene Basisadressen abgebildet sind. Diese lässt sich dann auch 
ganz einfach an Bibliotheksroutinen übergeben, aber auf die very special 
AVR optimization in Form von SBI und CBI kann man auf diese Weise 
natürlich nicht zugreifen.

> Da bei
> jedem Projekt dort andere Zahlen reingehören, muss die Lib doch eh immer
> neu übersetzt werden.

Dann ist es aber keine "Lib", sondern einfach nur ein Stück Programm, 
welches jeweils mit compiliert oder assembliert wird.

Vermeide in diesem Falle einfach, das "Bibliothek" zu nennen, um 
Verwirrung zu vermeiden.

: Bearbeitet durch Moderator
von Jan (Gast)


Lesenswert?

Jan schrieb:
> Da ich gerade noch andere Möglichkeiten untersuche.... gibt es eine
> einfache Lösung für folgendes Problem?
>
>
1
> .ifdef require_some_code
2
> some_code:
3
> ...
4
> .endif
5
> 
6
> ....
7
> 
8
> .ifdef require_some_other_code
9
> require_some_code = 1
10
> some_other_code:
11
> ...
12
> call some_code
13
> .endif
14
>
>
> ERROR: undefined reference to some_code
>
> Er müsste also weiter oben merken, dass der Code weiter unten benötigt
> wird. Anders gesagt müsste es eine Möglichkeit geben, irgendwas zu
> definieren, was  global gültig wäre. Da es 1001 Möglichkeiten gibt, was
> zu definieren, wollte ich mal fragen, ob da jemand was kennt.

Dann bleibt ja nur noch dieses als potentielle Lösung übrig, wenn man 
mal von einem "Stück dynamisch zusammengesetztem Programm" redet.

Folgender Code funktioniert übrigens problemlos. Ist also nicht so, dass 
das nicht schon irgendwie implementiert wäre:
1
cbio foobar,1
2
foobar=1

von Jan (Gast)


Lesenswert?

Upsi. Meinte natürlich "cbi"

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.