Forum: Compiler & IDEs mehrere Programme zusammen linken?


von joern (Gast)


Lesenswert?

Moin,
wir haben in einem Uni-Projekt einen SPARC-Prozessor so veraendert, dass 
er in einem interleaved Betrieb mehrere Threads gleichzeitig ausfuehren 
kann. Dem Programm erscheint der Prozessor dabei wie sechs parallele 
Rechner. Bei einem Reset beginnt der Prozessor jeden Thread an einer 
bestimmten Stelle im Bytecode. Das funktioniert mit einfachen Programmen 
bestens, aber wie mache ich es mit komplizierteren, in die Bibliotheken 
gelinkt werden? Gibt es eine Moeglichkeit, die einzelnen Threads soweit 
zu linken, dass die Bibliotheken schon eingebunden sind, und dann das 
ganze in ein Programm mit den entsprechenden Einsprungstellen zu linken?
Muss ich dabei fuer jedes Programm einen eigenen Linkerscript schreiben 
oder geht es mit einem zentralen? Speziell, wie behandle ich die 
einzelnen init-Sektionen und wie unterscheide ich die?

Gruss, Joern

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Dein Grundproblem ist, soweit ich verstanden habe, die Trennung der 
Adressräume der einzelnen Programme voneinander.

In üblichen Multitasking-Umgebungen hilft es enorm, wenn die CPU eine 
MMU hat und jedes Programm so seinen eigenen virtuellen Adressraum 
erhält, wenn der Scheduler des Betriebssystem dem Programm seinen 
Rechenzeitabschnitt zuteilt.

Was du mit "interleaved Betrieb" meinst, ist mir unklar. Habit ihr den 
üblichen Scheduler durch Veränderung der CPU per Hardware implementiert?

von joern (Gast)


Lesenswert?

Die normale SPARC-Implementierung besitzt eine siebenstufige Pipeline. 
Wir haben diese so veraendert, dass sie mit jedem Takt den Thread 
wechselt, so dass nur unabhaengige Threads gleichzeitig in der Pipeline 
sind, was einige Hazards zu vermeiden hilft und speziell bei uns die 
praktisch gleichzeitige Ausfuehrung mehrerer Interrupthandler 
ermoeglichen soll. Eine MMU besitzt der SPARC auch, die wollten wir aber 
ungern veraendern, weil dafuer die Zeit wohl nicht reicht. Statt dessen 
wuerden wir gern die einzelnen Threads so linken, dass sie ein Programm 
in einem zusammenhaengenden Adressraum ergeben. Das geht mit einfachen 
Programmen bestens, aber initialisierungs Code im .init-Segment stellen 
mich da vor ein Problem. Im Moment ist das Multithreading so geloest, 
dass der Prozessor nach einem Reset sieben verschiedene Einsprungstellen 
nacheinander laed. Kann ich nun die einzelnen .init-Segmente so linken, 
dass er fuer jeden Thread zu dessen .init-Code springt?

Gruss, Joern

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ich sehe da zwei Wege, verstehe aber den Benefit eurer Modifizierung 
nicht.

1/ Anlehnend an deine Idee wird jedes Programm für sich inkl. dem 
benötigten Startupcode und den Libraries gelinkt. Allerdings nicht wie 
üblich alle ab der gleichen Startadresse. Sondern jedes Programm bekommt 
seinen eigenen Adressraum. Eingestellt wird die Lage des Adressraums 
über die Linkercontrolskripte. Die fertigen Binärfiles werden dann 
zusammengefügt. Es kann mühsam sein, die Grösse der einzelnen Sektionen 
im Voraus abzuschätzen.

2/ Wenn man eine thread-safe C-Library und ggf. auch einen solchen 
Startupcode hat, dann kann man den mehrfachen Librarycode und ggf. 
Startupcode einsparen, indem man diesen Code einmal in eine eigene 
Sektion legt. Die Restprogramme werden wie bei 1/ erzeugt und in jeweils 
eigene Sektionen gelegt.

Bei beiden Methoden kann man Thread/Programm-gemeinsame Daten haben, die 
dann ebenfalls in eine eigene, gemeinsame RAM-Sektion kommen. Der 
Nachteil bei beiden Methoden ist die durch das Linken an eine absolute 
Adresse die feste Zuordnung der Programme zu einem Speicherbereich. 
Gerade das wäre der Benefit einer MMU - alle Programme würden an eine 
gleiche Startadresse gelinkt und dann durch die MMU auf unterschiedliche 
physikalische Adressen abgebildet.

Was ich nicht verstehe ist, welchen Nutzen das Ummodeln der Pipeline in 
eurem Sinn hat (ausser dem Lerneffekt und dem Forschungsdrang und dem 
Spass). Abgesehen von einer Performanceeinbusse durch den Verzicht auf 
die Pipeline und Möglichkeiten zur Codeoptimierung für eine CPU mit 
Pipeline sehe ich da viele Herausforderungen gegenüber einem 
konventionellen Kernel mit Scheduler, der sich gleichzeitug auch ale 
Einziger um die Hardwareresourcen (Interrupts, Periferie wie z.B. UART, 
...) kümmern kann. Wenn eure Threads/Programme solche Resourcen wollen, 
wird es IMHO mit eurem Verfahren ohne Kernel schwierig.

von joern (Gast)


Lesenswert?

Danke erstmal, das hoert sich doch schon ziemlich hilfreich an. Kann man 
den Linker irgendwie mit dem Verbinden der einzelnen Programme betrauen? 
Schließlich moechte ich die Einsprungstellen alle am Anfang haben, da 
eine Assemblerdatei einlinken und von der aus zu den jeweiligen 
Prozeduren springen. Das ginge zwar auch noch irgendwie so, waere aber 
mit dem Linker wohl weniger umstaendlich.
Das Projekt ist natuerlich ziemlich akademisch und auch nicht so der 
richtige Spass. Der einzige Vorteil dieser Interleaved Pipeline ist die 
Moeglichkeit, die Worst Case Execution Time einschaetzen zu koennen und 
gleichzeitig beliebig unvorhersehbare (auch statistisch unvorhersehbare) 
asynchrone Interrupts behandeln zu koennen. Geopfert wird dabei neben 
der zusaetzlichen Chipflaeche natuerlich jede Menge Leistung.
Ich werde dann doch mal einen Blick in die MMU werfen, auch wenn eine 
Anpassung dort wohl den Umfang des Projektes sprengen duerfte.

Gruss, Joern

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Oh, für das Verbinden den einzelnen Programme halte ich den Linker für 
zu mächtig.

Der Linker arbeitet auf Objektcode-Ebene, d.h. alle Symbole sind noch 
sichtbar. In den einzelnen Programmen sind bei Alternative 1 alle 
Symbole kritisch, die gleich sind; bei Alternative 2 einige die Probleme 
machen können (z.B. main) und einige, die harmlos sind (z.B. die aus der 
thread-safe Library). Das wird ein Riesenkuddelmuddel wg. mehrfachen 
Definitionen oder man muss alle kritischen Symbole unterscheidbar machen 
;-(

So ein Tool, das wie Objcopy arbeitet, wäre wohl besser geeignet.
http://www.gnu.org/software/binutils/manual/html_chapter/binutils_3.html

Die Arbeitsweise wäre, aus allen gelinkten Programmen und dem 
übersetzten Assemblerfile zunächst Binaries zu machen. Dann diese per 
Shell copy binär zu einem Megabinary aneinander hängen. Das Eintragen 
der Einsprungadressen in das Megabinary kann man banal mit einem 
Binärpatch im Endprodukt oder im übersetzten Assemblerfile machen oder 
gleich im Assemblerfile hart als Konstante codieren. Anschliessend das 
Megabinary ggf. in ein Hexfile o.ä. umwandeln, so wie es das 
Programmertool braucht.

Du ahnst sicher den Haken dahinter. Man braucht von Anfang an eine Idee 
wo die Startadressen zu liegen kommen und wie gross die Speicherslots 
für die Programme sind, um das Linkerskript zu machen... Entweder brutal 
indem man den realen Spricher durch die Zahl der Programme teilt oder 
indem man eine Versuchsserie fährt und den Platz dann nach Bedarf 
zuteilt.

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.