Grundsystem: von GRUB, Kernel und C/C++

  • Thread starter Thread starter DerMitSkill
  • Start date Start date
D

DerMitSkill

Guest
Hallo,

auf meinem Weg zum minimalen des Minimalen, gar minimaler als LFS, folgende Theorie und Fragen:

Ein Live-System ist von CD gebootet. Als erstes partitioniere ich die Festplatte, erstelle ein Dateisystem und mounte die Partition. Dann kompiliere ich GRUB sowie den Linux-Kernel auf dem Live-System, kopiere die entstandenen Dateien auf die Festplatte und konfiguriere GRUB entsprechend.

Schon könnte ich das System booten, richtig?

Als nächstes nehme ich meine selbstgeschriebe und bereits kompilierte C/C++-Anwendung (nehmen wir einen einfachen HTTP-Server, der bei Aufruf der IP ein "Hallo" ausgibt) und kopiere diese über das Live-System auf die Festplatte.

Kurze Zwischenfrage: Ich bin erst am Anfang mit C/C++. Wird zum Betrieb der kompilierten Anwendung noch eine C-Libary benötigt? Ich gehe zur Zeit davon aus, dass der Compiler sich die benötigten Inhalte beim kompilieren holt und alles, so wie er es brauch, in die ausführbare Anwendung packt. Liege ich damit richtig?

Nun mein Problem: Wie starte ich meine Anwendung? Bash gibt's nicht um es manuell zu starten, was ich aber auch nicht will. Wie stelle ich es an, dass die Anwendung (mit möglichst keinem/minimalen Overhead oder zusätzlicher Software) nach dem Boot-Vorgang gestartet wird?

Ich will auf dem System an sich weder kompilieren können, noch mittels "cd" durch's Dateisystem huschen, das erfolgt alles von einem Live-System, das von CD gebootet wird.

Wie praktikabel und produktiv einsetzbar das ist, ist mir bewusst, nämlich so gut wie gar nicht. Mein Ziel ist es, zu lernen, zu verstehen und zu versuchen.. reine Freude an etwas eigenem und extrem minimalem :)

Trotz allem hab ich das Gefühl, dass etwas grundlegendes fehlt, damit es so funktioniert. Das geht u.a. so Richtung Netzwerk (woher soll er wissen, welche IP ihm ist?)..

Viele Grüße und vielen Dank
 
Ein Live-System ist von CD gebootet. Als erstes partitioniere ich die Festplatte, erstelle ein Dateisystem und mounte die Partition. Dann kompiliere ich GRUB sowie den Linux-Kernel auf dem Live-System, kopiere die entstandenen Dateien auf die Festplatte und konfiguriere GRUB entsprechend.

Schon könnte ich das System booten, richtig?

Nicht ganz. Du benötigst verschiedene Libs ohne die dein System nichts macht, es seiden du kompilierst alles statisch. Du brauchst auch ein initsystem (z.B. sysinit-v, upstart oder systemd). Dann noch irgendeine Shell und die essentiellen Linux-Commands (GNU).

Als nächstes nehme ich meine selbstgeschriebe und bereits kompilierte C/C++-Anwendung (nehmen wir einen einfachen HTTP-Server, der bei Aufruf der IP ein "Hallo" ausgibt) und kopiere diese über das Live-System auf die Festplatte.
Möglicherweise läuft dein Programm nicht, wenn du eine andere Version der libc hast, außer du kompilierst es statisch. Die Architektur muss auch noch berücksichtigt werden. Du kannst z.B. kein x86_64 Programm auf einer x86 Architektur ausführen. Wenn ich das richtig verstanden habe, willst du die Programme aber auf dem gleichen System kompilieren und wobei das LiveSystem von der CD deinem, welches du installierst, ähnlich sein soll.

Kurze Zwischenfrage: Ich bin erst am Anfang mit C/C++. Wird zum Betrieb der kompilierten Anwendung noch eine C-Libary benötigt? Ich gehe zur Zeit davon aus, dass der Compiler sich die benötigten Inhalte beim kompilieren holt und alles, so wie er es brauch, in die ausführbare Anwendung packt. Liege ich damit richtig?
Das wäre echt ein Traum. Wenn dann noch wirklich alle Abhängigkeiten erfüllt würden und alles fehlerfrei durchläuft, wäre das echt viel Geld wert.
Der Kompiler macht nichts von alleine. Du musst dafür sorgen, dass die Headerdateien der Libs vorhanden sind, da du ansonsten dein Programm nicht kompilieren kannst.


Nun mein Problem: Wie starte ich meine Anwendung? Bash gibt's nicht um es manuell zu starten, was ich aber auch nicht will. Wie stelle ich es an, dass die Anwendung (mit möglichst keinem/minimalen Overhead oder zusätzlicher Software) nach dem Boot-Vorgang gestartet wird?
Gute Frage. Ich würde jetzt sagen über ein init-script. Dies würde dann aber eine Shell benötigen (nicht bash, z.B. ash oder dash), es seiden du nutzt systemd, welches aber nicht unbedingt ausgereift ist und noch dbus-daemon benötigt. Such mal nach einer Linux-Distribution für Embedded-Systems.

Ich will auf dem System an sich weder kompilieren können, noch mittels "cd" durch's Dateisystem huschen, das erfolgt alles von einem Live-System, das von CD gebootet wird.

Hast du dir LFS schonmal angesehen? Ich hab es bisher vermieden. Vielleicht bringt dich Gentoo weiter. Wobei wieder hier zwangsweise gcc installiert wird, der Portage und paar esentielle tools, ohne die nichts geht.

Wie praktikabel und produktiv einsetzbar das ist, ist mir bewusst, nämlich so gut wie gar nicht. Mein Ziel ist es, zu lernen, zu verstehen und zu versuchen.. reine Freude an etwas eigenem und extrem minimalem :)
Also das würde ich nicht sagen. Es gibt durchaus Hardware auf der ein minimales System notwendig ist (z.B. http://www.alix-board.de/produkte/alix3d3.html). Wenn man mit wenig RAM handeln muss, überlegt man sich zweimal welche Dienste man einsetzt. Ein Apache2 wäre z.B. auf der Hardware der Horror schlechthin. Hingegen würde nginx oder besser thttpd Sinn machen.


Trotz allem hab ich das Gefühl, dass etwas grundlegendes fehlt, damit es so funktioniert. Das geht u.a. so Richtung Netzwerk (woher soll er wissen, welche IP ihm ist?)..
Kernel lädt alle Module für Netzwerk usw. Userspaceprogramme wie ip, route, ifconfig usw. legen IP, routen usw. fest. Sieh dir mal LFS an. Wenn du so lernwillig bist, wirst du das schon so umbiegen wie du es haben willst.

PS: Sorry, musste soviel Zittieren, damit es einen Zusammenhang ergibt.
 
Vielen Dank für Deine Antwort, DeaD_EyE! :)

Vorab: LFS habe ich mir angesehen und auch schon durchgearbeitet.

Nicht ganz. Du benötigst verschiedene Libs ohne die dein System nichts macht, es seiden du kompilierst alles statisch. Du brauchst auch ein initsystem (z.B. sysinit-v, upstart oder systemd). Dann noch irgendeine Shell und die essentiellen Linux-Commands (GNU).

Welche Libs meinst Du?


bzgl. init-System:
/init/main.c des Linux-Kernel-Source said:
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");

Demnach wird eine dieser Dateien gestartet. Theoretisch könnte ich, wenn ich init (und weitere Software) nicht benötige, meine Anwendung als diese Datei ablegen bzw. auf meine Anwendung linken.. oder wäre das zu einfach?
Siehe ebenfalls hier, Punkt 8.


Nun ja.. ein System bootet ja auch ohne Shell und die Commands (wie cp, cd, passwd usw.). Zumindest ein LFS ohne die Commands hatte ich schon oben.. war halt dementsprechend recht unbenutzbar :D Aber wenn ich etwas an dem System ändern will boote ich ja das Live-System von CD, mounte die Festplatte und arbeite so..


Möglicherweise läuft dein Programm nicht, wenn du eine andere Version der libc hast, außer du kompilierst es statisch. Die Architektur muss auch noch berücksichtigt werden. Du kannst z.B. kein x86_64 Programm auf einer x86 Architektur ausführen. Wenn ich das richtig verstanden habe, willst du die Programme aber auf dem gleichen System kompilieren und wobei das LiveSystem von der CD deinem, welches du installierst, ähnlich sein soll.

Das ist klar, korrekt.


Das wäre echt ein Traum. Wenn dann noch wirklich alle Abhängigkeiten erfüllt würden und alles fehlerfrei durchläuft, wäre das echt viel Geld wert.
Der Kompiler macht nichts von alleine. Du musst dafür sorgen, dass die Headerdateien der Libs vorhanden sind, da du ansonsten dein Programm nicht kompilieren kannst.

Meine Anwendung kompiliere ich ja auf dem Live-System, wo selbstverständlich alle Abhängigkeiten erfüllt werden. Auf dem "neuen" System, auf dem die bereits kompilierte Anwendung zum Einsatz kommt, soll ja so wenig wie möglich drauf sein.

Wenn ich meine Anwendung nun statisch kompiliere, kommen alle Abhängigkeiten in die Anwendung, richtig?

So verstehe ich es zumindest aus diesem Wikipedia-Text:
Wikipedia said:
Statische Bibliotheken sind bereits vorab kompilierter Code. Eine statische Bibliothek wird nach dem Kompiliervorgang des Programms durch einen so genannten Linker mit dem Kompilat verbunden – er setzt aus Bibliothek und Programm ein ausführbares Programm oder auch eine andere ausführbare Komponente zusammen.
Der Linker sucht aus den zugeordneten Bibliotheksdateien die referenzierten Komponenten (Unterprogramme oder Daten) heraus, auf die aus dem Programm verwiesen wird (und für die es im Programm keine Implementierung gibt), und hängt sie dann an das Programm an. Die so entstehende Datei wird entsprechend größer.


Gute Frage. Ich würde jetzt sagen über ein init-script. Dies würde dann aber eine Shell benötigen (nicht bash, z.B. ash oder dash), es seiden du nutzt systemd, welches aber nicht unbedingt ausgereift ist und noch dbus-daemon benötigt. Such mal nach einer Linux-Distribution für Embedded-Systems.

Schau ich mir mal an..


Also das würde ich nicht sagen. Es gibt durchaus Hardware auf der ein minimales System notwendig ist (z.B. http://www.alix-board.de/produkte/alix3d3.html). Wenn man mit wenig RAM handeln muss, überlegt man sich zweimal welche Dienste man einsetzt. Ein Apache2 wäre z.B. auf der Hardware der Horror schlechthin. Hingegen würde nginx oder besser thttpd Sinn machen.

Das ist klar. Mit der Aussage wollte ich den Leuten vorkommen, die mir dann mit dem riesen Aufwand der Wartbarkeit kommen und meinen, das es mit 'nem Debian und der Software aus den Paketquellen auch getan wäre.


Kernel lädt alle Module für Netzwerk usw. Userspaceprogramme wie ip, route, ifconfig usw. legen IP, routen usw. fest. Sieh dir mal LFS an. Wenn du so lernwillig bist, wirst du das schon so umbiegen wie du es haben willst.

Schau ich mir mal an..
 
Last edited by a moderator:
Welche Libs meinst Du?

ldd ist dein Freund.

Code:
ldd /bin/sh
        libncurses.so.5 => /lib/libncurses.so.5 (0x40026000)
        libdl.so.2 => /lib/libdl.so.2 (0x40060000)
        libc.so.6 => /lib/libc.so.6 (0x40064000)
        /lib/ld-linux.so.2 (0x40000000)

 ldd /sbin/ip
        libresolv.so.2 => /lib/libresolv.so.2 (0x40026000)
        libdl.so.2 => /lib/libdl.so.2 (0x4003a000)
        libc.so.6 => /lib/libc.so.6 (0x4003e000)
        /lib/ld-linux.so.2 (0x40000000)

 ldd /sbin/init
        libsepol.so.1 => /lib/libsepol.so.1 (0x40026000)
        libselinux.so.1 => /lib/libselinux.so.1 (0x4005b000)
        libc.so.6 => /lib/libc.so.6 (0x40076000)
        libdl.so.2 => /lib/libdl.so.2 (0x401bb000)
        /lib/ld-linux.so.2 (0x40000000)

 ldd /bin/cp
        libselinux.so.1 => /lib/libselinux.so.1 (0x40026000)
        librt.so.1 => /lib/librt.so.1 (0x40041000)
        libacl.so.1 => /lib/libacl.so.1 (0x4004a000)
        libattr.so.1 => /lib/libattr.so.1 (0x40051000)
        libc.so.6 => /lib/libc.so.6 (0x40057000)
        libdl.so.2 => /lib/libdl.so.2 (0x4019c000)
        /lib/ld-linux.so.2 (0x40000000)
        libpthread.so.0 => /lib/libpthread.so.0 (0x401a0000)

....

Wenn du dein komplettes System statisch kompilierst, brauchst du überhaupt keine Libs. Ich denke mal, dass es aber keinen Sinn macht. Die ausführbaren Binärdateien werden dadurch noch größer und der Vorteil von Shared Libs ist nicht gegeben. Im Endeffekt würde es mehr Speicher kosten, wenn man viele statish kompilierte Programme ausführt, als diese dynamisch zu linken. D.h. wenn schon ein Programm läuft, welches die libdl benötigt, muss nicht noch eine Version geladen werden, wenn du noch ein Programm startest, welches diese Lib braucht.

Das mit Debian ist gar nicht so abwegig. Du kannst auch ein minimales Debiansystem installieren, wodurch die Wartung um einiges erleichtert wird. Dich zwingt ja niemand eine grafische Umgebung zu installieren. Du könntest einfach die Netinstall verwenden und alle Tasks abwählen. Dann wird nur das Grundsystem installiert. Es wird dann noch nichteinmal der openssh-server installiert. Der einzige Nachteil ist dann aber, dass z.B. Python und Perl automatisch installiert wird. Ich wüsste jetzt auch nicht, ob es überhaupt möglich ist, die Installation zu vermeiden. Viele Systemtools benötigen Perl oder Python. Du könntest dir auf jeden Fall viel Arbeit ersparen und dich voll und ganz auf das Programmieren konzentrieren. Sollte dir mal eine Lib fehlen, kannst du diese mit dem Paketmanager installieren. Wenn du ein Programm kompilieren willst, welches die Header-Dateien benötigt, kannst du das dazugehörige Paket mit -dev installieren. Bei LSB müsstest du dir erst aus den Quellen die Lib erstellen. Das kannst aber auch unter Debian Pakete aus den Quellen compilieren.

Ansonsten könntest du dich mal hier umsehen: http://www.linuxlernen.com/distributionen.html

Wenn du lieber alles aus einer Hand haben willst und dazu eine gute vollständige Dokumentation, kann ich dir FreeBSD empfehlen. Da lernst du auch etwas mehr über UNIX. Ich selbst konnte mich noch nicht aufraffen mal FreeBSD zu testen. Aber es kann nicht schaden sich auch mal damit zu beschäftigen. Immerhin wird dort einiges unterstützt, was zwar auch unter Linux funktioniert, aber durch die unterschiedlichen Lizenzen nur schwer vereinbar ist. Mein Lieblingsbeispiel ist z.B. das Dateisystem zfs. Das kannst du unter FreeBSD ohne Probleme einrichten. Unter Linux bleibt dir nichts anderes möglich als ZFS über Fuse laufen zu lassen oder das Kernel-Modul selbst zu kompilieren (ist der bessere Weg).

Zu dem Thema wird sicherlich noch jemand etwas schreiben, der mehr Ahnung davon hat.

PS: Manche Sätze könnten keinen Sinn ergeben. Ist schon zu spät...
 
Du brauchst auch ein initsystem (z.B. sysinit-v, upstart oder systemd).

Nope, wenn nur ein Prozess gestartet werden soll, dann wird er vom Kernel aufgerufen und gut ist. Macht zwar wenig Sinn, würde aber funzen.

Man kann z.B. per Kernel-Parameter init=/bin/bash übergeben und nachdem der Kernel geladen wurde, wird man in einer Bash abgesetzt und kann weiter machen. Das gleiche würde auch mit einem Webserver gehen. Der Prozess bekommt die Nummer 1 und ist der Held.

Der Webserver wird entweder statisch gelinkt oder die Libs einfach mit in das Linux geschoben. Das wäre nix anderes, als ein chroot aufzubauen.
 
Wenn du dein komplettes System statisch kompilierst, brauchst du überhaupt keine Libs. Ich denke mal, dass es aber keinen Sinn macht.

Wenn nur ein Prozess laufen soll, dann isses egal.

Wenn du mit embedded Linux spielen magst, sieh dir mal OpenWRT an. Das kann man prima auf x86 kompilieren.
 
DeaD_EyE und PapaBaer, vielen Dank für Eure Antworten.


Siehe mein Kommentar beim zweiten Zitat von PapaBaer.

Man kann z.B. per Kernel-Parameter init=/bin/bash übergeben und nachdem der Kernel geladen wurde, wird man in einer Bash abgesetzt und kann weiter machen. Das gleiche würde auch mit einem Webserver gehen. Der Prozess bekommt die Nummer 1 und ist der Held.

Der Webserver wird entweder statisch gelinkt oder die Libs einfach mit in das Linux geschoben. Das wäre nix anderes, als ein chroot aufzubauen.

Das läuft wohl auf die Stelle im Linux-Kernel-Source hinaus, die ich oben zitiert habe, nur etwas eleganter, perfekt.

Wenn nur ein Prozess laufen soll, dann isses egal.

Eben. Keine anderen Programme greifen auf die Libs zu, da es nur dieses eine Programm gibt :)

Wenn du mit embedded Linux spielen magst, sieh dir mal OpenWRT an. Das kann man prima auf x86 kompilieren.

Schau ich mir mal an..
 
Jetzt bleibt noch eins: Netzwerkkonfiguration. Die Tools, die das übernehmen, müssen ja irgendwie auf den Kernel zugreifen oder es gibt Konfigurationsdateien, die der Kernel direkt ausließt.. ist doch sowas grundlegendes.
 
PS: Bei init=/bin/bash frage ich mich, ob / dann auch automatisch gemountet wird.

Da wird überhaupt nix gemacht. Das Root-FS ist da, weil das beim Booten als Paramter an den Kernel ging. Da wird nicht mal nach nem Passwort gefragt. Bash und sonst gar nüscht.
 
Soweit ich weiß greifen die Tools direkt auf die Gerätedateien zu. Sieh dir den Quellcode von IP oder ifconfig mal an. Da siehst du welche Syscalls gemacht werden. (http://ftp.de.debian.org/debian/pool/main/n/net-tools/net-tools_1.60.orig.tar.gz)

Der Quellcode ist nicht gerade ausführlich kommentiert.. da ist der Linux-Kernel besser.

Könnte mir jemand 'nen Tipp geben, wie ich das Festlegen der IP-Adresse, Netzmaske und des Gateway ohne zusätzliche Tools erledigen kann?
 
Kann dir leider deine eigentliche Frage nicht beantworten, weil ich so tief nicht im Kernel stecke.

Aber, du könntest dir busybox bauen und dann als init nicht den Webserver, sondern ein kleines Shell-Script starten, welches dir alles konfiguriert und dann den Webserver hoch zieht.
 
/net/ipv4/ipconfig.c des Linux-Kernel-Source said:
* Automatic Configuration of IP -- use DHCP, BOOTP, RARP, or
* user-supplied information to configure own IP address and routes.

Also mir sagt das, dass irgendetwas im Kernel steckt, dass die Aufgabe übernehmen kann..

.. und da liege ich wohl nicht ganz so falsch:

/net/ipv4/ipconfig.c des Linux-Kernel-Source said:
* Decode any IP configuration options in the "ip=" or "nfsaddrs=" kernel
* command line parameter. See Documentation/filesystems/nfs/nfsroot.txt.

/Documentation/filesystems/nfs/nfsroot.txt des Linux-Kernel-Source said:
2.) Kernel command line
[..]
ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>

War irgendwie logisch, oder? :p

Lieg ich jetzt da richtig, dass ich kein ifconfig/iproute2 mehr brauche? :)
 
Last edited by a moderator:
Geil :D

Es ist einfach schön, wenn man seine Theorie bestätigt bekommt und so nicht die ganze Zeit auf dem Holzweg war :)

Festplatte:
Code:
/boot/grub/               GRUB mit seinen Dateien
/boot/linux-3.0.1         Statischer Linux-Kernel
/anwendung                Eigene Anwendung

Desweiteren gibt's die System.map zum Kernel. Benötigt die der Kernel oder nur evtl. Anwendungen?

/proc kommt ebenfalls dazu, was ja vom Kernel erzeugt wird, richtig?

Jetzt mal ganz blöde: Welche Dateien kommen noch dazu? z.B. loggt der Linux-Kernel von alleine irgendwo hin oder hab ich gar kein Log?
 
Last edited by a moderator:
Desweiteren gibt's die System.map zum Kernel. Benötigt die der Kernel oder nur evtl. Anwendungen?
Weder noch. Die System.map ist eigentlich nur für die Auswertung von Kernel dumps nützlich und beinhaltet ein Mapping (".map") von Symbolen, wie internen Funktionsnamen, zu Speicheradressen.

Jetzt mal ganz blöde: Welche Dateien kommen noch dazu? z.B. loggt der Linux-Kernel von alleine irgendwo hin oder hab ich gar kein Log?
Der Linux-Kernel loggt in den Kernel-Ring-Puffer, siehe `dmesg`.
 
Nur so als Anregung... GRUB ist auch überflüssig, der Kernel enthält einen eigenen Bootsektor (dadurch kann er z.B. starten wenn er mit dd auf eine Diskette geschrieben wurde). Einige Parameter wie Videomodus oder Bootdevice können dazu im Kernelimage angepasst werden, mit rdev.

Als ich das zuletzt gemacht habe gab es allerdings wirklich noch Disketten, wer weiss was sich seitdem geändert hat...
 
Ok, seit 2.6 geht das wohl nicht mehr, mit hd -n 512 /vmlinuz sieht man "Direct booting from floppy is no longer supported".

Früher ging das mal so: http://tldp.org/LDP/lki/lki-1.html
Im Prinzip ein eigener Bootloader der den restlichen Kernel geladen und gestartet hat. Dadurch konnte man den Kernel irgendwo hin schreiben wo das BIOS einen Bootloader erwartete (Diskette, erster Sektor der Festplatte) und ohne Dateisystem booten.

Schade dass es raus ist, normalerweise wird bei Linux recht wenig weggeworfen...
 
Die Funktion wird dank UEFI auf den unterstützten Plattformen nicht mehr benötigt.
Zudem passt ein aktueller Linux kaum noch auf 1,44/2,88 MB ;)
 
Back
Top