Assemblerfunktionen in .S 'inlinen'

OP #363441
Lesenswert?

Hallo,

besteht die Möglichkeit Funktionen in .S-Dateien so zu deklarieren, daß
der Linker die Dinger als 'inline' betrachtet?

Beispiel:
Die Funktionen SPI_Init() und UART_Init() werden nur einmal
aufgerufen.
Um mir das 'rcall' und 'ret' des AVR-GCC zu sparen hätte ich die
gerne als 'inline' deklariert, aber mit dem Vorteil eines noch
lesbaren Codes (also nicht direkt als inline-asm):

in .h
void UART_Init(uint16_t UBRR);

in .S

.global UART_Init
.func UART_Init
UART_Init:
  out    _SFR_IO_ADDR(UBRRH), 25
  out    _SFR_IO_ADDR(UBRRL), 24
  ldi    18, (1<<RXEN)|(1<<TXEN)
  out    _SFR_IO_ADDR(UCSRB), 18
  // 8 Data, 2 Stop
  ldi    18, (1<<URSEL)|(1<<USBS)|(3<<UCSZ0)
  out    _SFR_IO_ADDR(UCSRC), 18
  ret
.endfunc

Grüße,
Frekazoid
OP #363444
Lesenswert?

@Jörg:
Oder meinst Du 'nur diese Funktion' in 'C'?
Immerhin kommt dann auch nur ein .o raus und die Teile kommen
schließlich alle in eine LIB. Wäre vielleicht eine Lösung
(der Linker scheint Objekte als Einheit zu sehen und linkt diese
komplett. Deswegen die Teilung der Module in einzelne
Funktionsobjekte).
OP #363450
Lesenswert?

Kompromiss: Die Funktion ist jetzt 'sichtbar' für andere.

Wenn der Linker die Sache erledigen könnte, hätte ich 'ne Lib gemacht
und nur ein .h-File mit der Deklaration benötigt. Stört bei einer
Funktion wie SPI_Init() nicht wirklich, aber für die Zukunft hätte ich
gerne die Funktion in einer Lib um eventuell Code weiterzugeben - ohne
das jemand den Quellcode kennt.

Außerdem funktioniert das wohl nur mit Libs (und einzelnen Objekten pro
Funktion), damit der Linker sich Teile rausnimmt welche er benötigt.
Sonst wird Code mitgelinkt, welcher nicht benötigt wird.
#363451
Lesenswert?

Aehm
Wenn Du eine Library weitergibst, dann gibst
Du weiter
  * die Library
  * den/die zugehoerigen Header-Files

Derjenige, dem Du die Library gibst, kriegt Deinen
Source Code nie zu sehen.

> Sonst wird Code mitgelinkt, welcher nicht benötigt wird.

Das halte ich fuer ein Geruecht.
Wenn es in den letzten 20 Jahren einen Linker gegeben
hat, der eine Library ohne Analyse des Einsatzes von
Funktion komplett einbindet, dann ist der Programmierer
dieses Linkers mit einem nassen Fetzen erschlagen worden
und die Firma laengst bankrott.
OP #363453
Lesenswert?

@Karl:
Ist aber so. Die Objekte einer Lib werden vom GNU-Linker als Einheit
betrachtet (http://www.mikrocontroller.net/forum/read-2-193465.html).
Ist von mir auch verifiziert worden ;-)
NUR wenn jede Funktion ein Objekt ist, werden andere nicht beachtet.
Zudem ist es so, wenn Dein Programm eine Funktion Test() beinhaltet,
wird auch der Code gelinkt - ohne Rücksicht auf dessen Verwendung.
Laß Dir mal ein .lss oder .map generieren.
OP #363455
Lesenswert?

Ähm. Nachtrag:

@Karl:
> Wenn Du eine Library weitergibst, dann gibst
> Du weiter
>   * die Library
>   * den/die zugehoerigen Header-Files
> Derjenige, dem Du die Library gibst, kriegt Deinen
> Source Code nie zu sehen.
Das ist richtig. allerdings hab ich es bisher nicht gebacken bekommen
'inline static' wie es sich gehört im .h zu deklarieren und in .c zu
implementieren. Andere Funktionen gehen ;-)
#363456
Lesenswert?

Das ist das Wesen von 'inline'.

Um eine Funktion inline ersetzen zu koennen, muss
der Kompiler den Code sehen koennen. So einen
Code kannst Du daher nicht in eine Library packen,
sondern musst ihn so ausliefern, dass der Compiler
ihn auch zu Gesicht bekommt, wenn er die Aufruf-
stelle uebersetzt.

Ist ja auch logisch, wenn man bedenkt was inline
eigentlich macht.
#363458
Lesenswert?

Soweit ich weiss kann der Compiler nur inlinen, was im gleichen Source
File (bzw. darin eingebundenen Headerfile) steht. Jede Funktion die in
einem anderen .C oder .o File steht kann er nicht inlinen, weil er die
Datei beim compilieren ja nicht ansieht.
Und der Linker ist sowieso doof, der kann nix (ausser .o files
zusammenpackeln und Referenzen auflösen). Aber doch nie Code in ein
Object einfügen.

Just my 0.02 €
#363461
Lesenswert?

Soweit ich weiss, machen die im Linker eine (kleine)
Codeanalyse. Was ich nicht weiss ist, welche Restriktionen
der Linker anwendet, sprich was er noch inlined und was nicht.

Interessant ist das aber trotzdem. Dadurch koennte
inlining auch sprachuebergreifend (Assembler - C - C++ -
Fortran - was weiss ich noch was) angewendet werden. Auch
waere damit inlining aus einer Library heraus moeglich.
OP #363462
Lesenswert?

Hab jetzt einige Stunden experimentiert. Momentan sieht es wohl so aus,
daß diverse Vorteile von C gegenüber Assembler verschwimmen. Der Linker
jedenfalls bietet mir momentan nur zwei Möglichkeiten:

o ich pack diverse Funktionen in Einzelobjekte und diese
  in eine Library um ein 'cleveres' Linking zu erreichen.
  - Haufenweise Dateien für Module
  - Lib ist nur für einen AVR kompiliert (IO-Bereiche, RAM, Flash)
    und damit ziemlich eingeschränkt.
  + Linker wählt nur Funktionen die auch gebraucht werden.

o Das komplette Projekt wird für den aktuellen AVR kompiliert/gelinkt.
  + Flexibel gegenüber AVR-Wechsel
  - Kompletter Code ist im Binary
  - Änderungen in 'globalen' Modulen (Log, UART) müssen in anderen
    Projekten eingepflegt werden.

Ich hab mal mit den Optionen -ffunction-sections und --gc-sections
experimientiert -> nix.
Laut Google hat aber Jörg Wunsch die Linkerskripte so geändert, daß die
Optionen funktionieren.
Wenn man dem Linker das 'selektive Verhalten' ohne den Umweg über die
Libs angewöhnen könnte, wäre ich ja schon zufrieden. Das Einpflegen der
aktuellsten Moduldateien in die Projekte würde ich dann das CVS-System
machen lassen ;-)

Oder gibt es einen Tip eine Library, die z.B. auf IOs zugreift (die
AVR-spezifisch sind) flexibel zu gestalten?

Also Bitte an Jörg Wunsch (der ja auch relativ oft hier schreibt):
Erhöre mich ;-) Du scheinst ja den gleichen Wunsch gehabt zu haben ...

Grüße,
Freakazoid
Moderator Persönliche Seite #363463
Lesenswert?

> Laut Google hat aber Jörg Wunsch die Linkerskripte so geändert, daß
> die Optionen funktionieren.

Dann weiß Google hier mehr als ich. ;-)

Ich bin mir im Moment gerade nicht sicher, woran es liegt, dass
-ffunction-sections + --gc-sections nicht funktioniert.  Ich finde
persönlich diese Methode eher unsauber, da mein Standpunkt ist, dass
ein Entwickler wissen sollte, welche Funktionen voneinander unabhängig
sind und daher in eigene Quelldateien (und damit in eigene
Objektmodule) gehen können und welche nicht.  Ich halte das für
sauberer, als hinterher die Faulheit des Programmierers (die sich dann
auch in aller Regel in nicht mehr wirklich überschautem Code äußert)
durch irgendeine Heuristik des Linkers ausbügeln zu lassen.

Ein wenig haben wir uns jetzt vom ursprünglichen Subject wegbewegt.
Klar könnte der Linker wahrscheinlich auch noch derartige Funktionen
inline auflösen, aber ich frage mich, ob die wenigen gesparten CALL
und RET den Aufwand wirklich wert sind.

Prinzipiell kannst du dir auch die .initN-sections mal angucken, wobei
bei denen natürlich ganz besondere Vorsicht walten muss, wenn man
--gc-sections benutzt -- sonst ist die komplette Initialisierung
flöten gegangen.

So 100%ig klar ist mir dein Anspruch allerdings noch nicht, das gebe
ich zu.  Ich habe bislang noch keinen Code gesehen, den man nicht für
einen anderen Prozessor nicht ohnehin anpassen müsste, es sei denn, es
handelt sich um reine Arithmetik (also keinerlei IO-Zugriffe).  Daher
muss man für den IO-Bereich ohnehin entweder den Endkunden compilieren
lassen oder eine Bibliothek pro unterstütztem Prozessor mitgeben.  Für
reine Arithmetik kannst du ja so arbeiten, wie's die avr-libc selbst
macht: pro grundlegegender AVR-Architektur (derzeit also avr2 ...
avr5) baust du eine Bibliothek.

Vielleicht beschreibst du ja mal bisschen detaillierter, was du
wirklich genau vorhast.
OP #363464
Lesenswert?

Hallo,

erstmal danke für Deine Antwort. Ich hab die Aussage von 2003 auch nur
grob überflogen. Vielleicht hast Du ja auch einen 'Doppelgänger' ;-)

Ich finde nicht, daß es als 'Faulheit' eines Programmierers zu werten
ist, wenn er aus Modulsicht zusammengehörige Funktionen in eine Datei
packt. Es wird schnell unübersichtlich, wenn man jede Funktion einzeln
verpacken muß. Abgesehen davon versteh ich das Verhalten des Linkers
nicht einzelne Objekte NUR aus Libraries auszuwählen, aber aus einem
Gesamtprojekt nicht. Es muß also nicht nur jede Funktion einzeln in
Dateien stehen, sonmdern diese auch noch in Bibliotheken. Das ist ein
heiden Aufwand.
Es sollte für einen Linker ein Leichtes sein 'unused code' oder
Sektions zu entfernen. Bei manchen Architekturen kann er das ja auch.

Generell will ich auch keinen Anspruch erheben ;-)
Das mit den verschiedenen Prozessorarchitekturen und der Unmöglichkeit
diese in Bibliotheken abzubilden ist verständlich.
Allerdings wirft der Linker genau da mein Problem auf:
Wird der Code generell zusammen übersetzt (also ohne Libs), packt der
Linker ALLES zusammen. Auch unbenutzten Code. Da hilft es auch NICHT,
wenn man für jede Funktion eine eigene Datei hat. Das schafft er nur
bei Bibliotheken (siehe vorheriger Absatz).

BTW:
Es kann natürlich auch sein, daß ich mich 'vertestet' habe, aber
Google deckt sich mit meinem Ergebnis. Ein einfaches 'void Test() {
PIND = 1}' in einer Einzeldatei taucht immer im map und in der lss
auf. Da hilft auch kein Strippen von Symbolen ;-)
Moderator Persönliche Seite #363465
Lesenswert?

Ja, auf der Kommandozeile angegebene Objekte werden immer gelinkt.
Der Programmierer wird sich ja was dabei gedacht haben, dass er sie
angegeben hat.

So groß ist der Aufwand für Bibliotheken auch wieder nicht, zumal
Makefiles traditionell Möglichkeiten bieten, Bibliotheksmodule einzeln
zu aktualisieren.  Braucht vermutlich heute kaum noch jemand, mit
derzeitigen Rechnern ist eine Bibliothek auch from scratch ganz fix
neu zusammengezimmert.

Ansonsten: warum nicht zur Sortierung alles was zusammengehört in ein
Verzeichnis, und in diesem dann eine Datei pro Funktion?  Ich finde
das durchaus auch aufgeräumt.

Vielleicht bin ich ja einfach nur altmodisch. :-)
OP #363466
Lesenswert?

Hm. 'Altmodisch' ist meistens besser ;-)
Vielleicht liegt es auch am AVR-Studio und meiner Makefile-Unkenntnis
und dem darauf resultierendem blinden Vertrauen ;-)

Kleine Frage:
Deine Methode würde beim Linken (für eine neue Prozessorarchitektur)
eines Projektes erst die Bibliotheken aktualisieren (eventuell sogar
mit ArchitekturSuffix) und dann den Rest kompilieren und gegen diese
Libs linken?
Da braucht man wohl tiefgehendes Know-How, oder? Denke mal mit
AVRStudio steh ich da auf dem Schlauch.
Moderator Persönliche Seite #363467
Lesenswert?

Naja, mit dem AVR Studio allein wird das nicht gehen, auch Mfile ist
nicht mehr dafür gedacht.  Beide bieten ja eher eine vereinfachte
Sichtweise, die für kleinere Projekte die Makefile-Gebilde vor dem
Benutzer verstecken sollen.

Ein derartiges Build-System müsste man schon irgendwie designen.
Vielleicht mehrere build-Verzeichnisse für die einzelnen Unterstützten
Prozessoren, in die hinein dann mit unterschiedlichen -mmcu-Optionen
die gleichen Quellen hinein compiliert werden (ggf. noch mit
verschiedenen Namen der Zielbibliotheken).  Kann man mit der Hand
aufsetzen oder mit irgendwelchen Tools wie autoconf/automake, Cmake,
scons etc. pp.

Ehrlich gesagt, ich kann mir nicht vorstellen, wie man mit einem
derart primitiven Editor, wie er in AVR Studio drin ist, ein größeres
Projekt auch nur ansatzweise bewältigen will.  Der kann ja nichtmal
richtige reguläre Ausdrücke (alles mit ^$ etc. endet darin, dass er
den Suchbegriff nicht findet).  Ist sicher Geschmackssache,
Windowsnutzer scheinen mir ja eher zu Masochismus zu neigen, was
vernünftige Prozeduren zum Suchen und Ersetzen angeht. ;-)
#363472
Lesenswert?

> Es sollte für einen Linker ein Leichtes sein 'unused code' oder
> Sektions zu entfernen.

In C++ ist das zum Teil ganz schoen knifflig.
Stichwort: virtuelle Funktionen
Da gibt es (normalerweise) keinen einzigen direkten
Aufruf der Funktion und trotzdem wird sie zur Laufzeit
(indirekt) aufgerufen.

Wenn man nun nur einen gemeinsamen Linker für mehrere
Compiler benutzen will (und das will man normalerweise),
dann sitzt man in der Bredulie.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren