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.
Hmmm habe ich grad mal ausprobiert. "0 Bytes Flash used" :D Der hat mal eben alles weggekürzt.
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.
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?
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.
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
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.
#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.
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.
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
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 |
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.