So erstellen Sie eine Verknüpfung, die es normalen Benutzern ermöglicht, eine Anwendung mit Administratorrechten auszuführen. Einfacheres Ausführen von Anwendungen in Windows als Administrator, ohne UAC zu deaktivieren

Was ist, wenn Sie ein Programm ausführen müssen, es aber nicht installieren möchten? Zero Install zur Rettung!

Milliarden von Menschen auf der ganzen Welt verwenden Computer oder Laptops auf Betriebssystem Fenster. Normalerweise installieren wir Programme, danach belegen sie freien Speicherplatz und verwenden RAM... Dies verlangsamt die Geschwindigkeit des Computers.

Heute zeigen wir Ihnen, wie Sie die Leistung Ihres Computers steigern und den Arbeitsspeicher entlasten können. Dazu müssen Sie die erforderlichen Programme ausführen, ohne sie zu installieren.

Wie starte ich das Programm ohne Installation?

1. Laden Sie Zero Install herunter.

Laden Sie zunächst die Zero Install-Software herunter, mit der Sie Programme ausführen können, ohne sie auf Ihrem Computer installieren zu müssen.

2. Installieren Sie Zero-Install.

Nachdem Sie Zero Install heruntergeladen haben, doppelklicken Sie auf die Datei, um sie zu installieren. Dann renne neues Programm auf deinem Computer.

3. Klicken Sie auf indas Mauerwerk "Katalog".

Sobald Zero Install auf dem Computer gestartet wird oder Windows-Laptop, sollten Sie auf die Registerkarte "Katalog" gehen. Klicken Sie hier auf die Schaltfläche "Liste aktualisieren", um die Liste der verfügbaren Programme zu aktualisieren.

4. Wählen Sie ein auszuführendes Programm.

Schau dich gut um volle Liste verfügbaren Programme. Wenn Sie das gewünschte Programm finden, wählen Sie es aus und klicken Sie auf "Ausführen". Einige Programme können wählen Firefox-Browser oder Mozilla zu laufen. Warten Sie einfach, bis es vollständig geladen ist Software, danach können Sie es ohne Installation auf Ihrem Computer ausführen.


Zusammenfassend

Wenn Ihr Computer nicht über genügend freien Speicher oder Strom verfügt, um das Programm auszuführen, können Sie Zero Install verwenden. Ich denke, dies ist eine großartige Möglichkeit, Ihren Computer nicht mit Programmen zu überladen, die Sie gleichzeitig benötigen.

Außerdem verfügt Ihr Computer möglicherweise nicht über genügend Leistung, um bestimmte Programme wie Eclipse IDE, JetBrains, NetBeans usw. auszuführen. Das sind wirklich schwere Entwicklerprogramme, die verbrauchen große Menge Arbeitsspeicher.

Zero Install hilft Ihnen, diese und viele andere Programme auszuführen, ohne sie auf Ihrem Computer zu installieren.

Das Wichtigste wurde nicht ausführlich genug beschrieben: Wie läuft dieser Code auf echter Hardware ab? So erstellen Sie Ihre eigenen Boot-Diskette? In diesem Artikel werden wir all diese Fragen im Detail beantworten (einige dieser Fragen wurden im vorherigen Artikel behandelt, aber zur besseren Lesbarkeit erlauben wir uns eine kleine Vervielfältigung des Materials).

Im Internet gibt es eine Vielzahl von Beschreibungen und Tutorials, wie man sein eigenes Mini-OS schreibt, es gibt sogar Hunderte von vorgefertigten kleinen Hobby-Betriebssystemen. Eine der wertvollsten Ressourcen zu diesem Thema, die ich hervorheben möchte, ist das Portal osdev.org. Um den vorherigen Artikel über PCI zu ergänzen (und die Möglichkeit, nachfolgende Artikel über die verschiedenen Funktionen zu schreiben, die in jedem modernen Betriebssystem vorhanden sind), beschreiben wir Schritt für Schritt Anweisungen zum Erstellen einer bootfähigen Diskette mit einem vertrauten Programm in der Sprache C. Wir haben versucht, so viele Details wie möglich zu schreiben, damit Sie alles selbst herausfinden können.

Das Ziel also: So wenig Aufwand wie möglich aufwenden, eigene erstellen bootfähiges USB-Laufwerk, die einfach das klassische „Hello World“ auf den Computerbildschirm druckt.

Um genauer zu sein, müssen wir in den geschützten Modus mit deaktiviertem Paging und Interrupts "kommen" - den einfachsten Modus des Prozessors mit dem üblichen Verhalten für ein einfaches Konsolenprogramm. Der klügste Weg, ein solches Ziel zu erreichen, besteht darin, einen Kernel zu bauen, der das Multiboot-Format unterstützt, und ihn mit dem beliebten . zu booten Bootloader Grub... Eine Alternative zu dieser Lösung besteht darin, einen eigenen Volume Boot Record (VBR) zu schreiben, der den geschriebenen eigenen Loader (Loader) laden würde. Zumindest ein anständiger Bootloader sollte in der Lage sein, mit einer Festplatte, einem Dateisystem und dem Parsen von Elf-Images zu arbeiten. Das bedeutet, dass Sie viel Assemblercode und viel C-Code schreiben müssen, kurz gesagt, es ist einfacher, Grub zu verwenden, das bereits alles weiß, was Sie tun müssen.

Zu Beginn erfordern weitere Aktionen einen bestimmten Satz von Compilern und Dienstprogrammen. Am einfachsten ist es, eine Art Linux (z. B. Ubuntu) zu verwenden, da es bereits alles enthält, was Sie zum Erstellen eines bootfähigen USB-Flash-Laufwerks benötigen. Wenn Sie es gewohnt sind, mit Windows zu arbeiten, können Sie konfigurieren virtuelle Maschine mit Linux (mit Virtual Box oder VMware Workstation).

Wenn Sie verwenden Linux Ubuntu, dann müssen Sie zunächst mehrere Dienstprogramme installieren:
1. Grub. Verwenden Sie dazu den Befehl:

Sudo apt-get install grub

2. Qemu. Es wird benötigt, um alles schnell zu testen und zu debuggen (Link zum Artikel über den Debugger), dafür ist der Befehl ähnlich:

Sudo apt-get install qemu

Unser Plan sieht jetzt so aus:
1.Erstellen Sie ein C-Programm, das eine Zeichenfolge auf dem Bildschirm ausgibt.
2. Erstellen Sie daraus ein Image (kernel.bin) im Miniboot-Format, damit es zum Booten mit GRUB verfügbar ist.
3. Erstellen Sie eine bootfähige Disk-Image-Datei und formatieren Sie sie.
4. Installieren Sie Grub auf diesem Image.
5. Kopieren Sie das erstellte Programm (kernel.bin) auf die Diskette.
6. Schreiben Sie das Image auf ein physisches Medium oder führen Sie es in qemu aus.

und der Systemstartprozess:

Dazu müssen Sie mehrere Dateien und Verzeichnisse erstellen:

Schritt 1. Generieren des Zielprogramm-(Kernel-)Codes:

Erstellen Sie eine Datei kernel.c, die den folgenden Code enthält, um eine Meldung auf dem Bildschirm zu drucken:

#include "printf.h" #include "screen.h" #include "types.h" void main (void) (clear_screen (); printf ("n >>> Hello World! n");)

Hier ist alles vertraut und einfach. Das Hinzufügen der Funktionen printf und clear_screen wird später besprochen. In der Zwischenzeit müssen wir diesen Code mit allem Notwendigen ergänzen, damit er von Grub geladen werden kann.
Damit der Kernel im Multiboot-Format vorliegt, wird in den ersten 8 Kilobyte des Kernel-Images die folgende Struktur benötigt:

Wenn alle angegebenen Bedingungen erfüllt sind, übergibt Grub einen Zeiger auf die Multiboot-Informationsstruktur und den Wert 0x1BADB002 durch die Register % eax bzw. % ebx. Die Multiboot-Informationsstruktur enthält verschiedene Informationen, einschließlich einer Liste der geladenen Module und ihrer Position, die möglicherweise für das weitere Laden des Systems benötigt werden.
Damit die Datei mit dem Programm die notwendigen Signaturen enthält, erstellen wir eine Datei loader.s mit folgendem Inhalt:

Text .global loader # Einstiegspunkt für Linker sichtbar machen # Multiboot-Header einrichten - Details siehe GRUB-Dokumentation .set FLAGS, 0x0 # Dies ist das Multiboot-"Flag"-Feld .set MAGIC, 0x1BADB002 # "magische Nummer" lässt den Bootloader finden der Header .set CHECKSUM, - (MAGIC + FLAGS) # Prüfsumme erforderlich .align 4 .long MAGIC .long FLAGS .long CHECKSUM # anfänglichen Kernel-Stack-Speicherplatz reservieren .set STACKSIZE, 0x4000 # dh 16k. .lcomm Stack, STACKSIZE # 16k Stack reservieren .comm mbd, 4 # wir werden dies in kmain .comm magic verwenden, 4 # wir werden dies in kmain loader verwenden: movl $ (stack + STACKSIZE),% esp # den Stack einrichten movl% eax, magic # Multiboot magische Zahl movl% ebx, mbd # Multiboot-Datenstruktur call main # call C-Code cli hang: hlt # halt machine sollte der Kernel jmp hang zurückgeben

Schauen wir uns den Code genauer an. Dieser Code stammt fast unverändert aus wiki.osdev.org/Bare_Bones. Da gcc für die Kompilierung verwendet wird, wird die GAS-Syntax verwendet. Schauen wir uns genauer an, was dieser Code macht.

Der gesamte nachfolgende Code fällt in den ausführbaren Abschnitt .text.

Globaler Lader

Wir deklarieren das Loader-Symbol für den Linker sichtbar. Dies ist erforderlich, da der Linker den Loader als Einstiegspunkt verwendet.

FLAGS setzen, 0x0 # FLAGS zuweisen = 0x0 .set MAGIC, 0x1BADB002 # MAGIC zuweisen = 0x1BADB002 .set CHECKSUM, - (MAGIC + FLAGS) # zuweisen CHECKSUM = - (MAGIC + FLAGS) .align 4 # nachfolgende Daten um 4 Byte ausrichten. long MAGIC # Platziere den MAGIC-Wert an der aktuellen Adresse .long FLAGS # Platziere den FLAGS-Wert an der aktuellen Adresse .long CHECKSUM # Platziere den CHECKSUM-Wert an der aktuellen Adresse

Dieser Code generiert eine Multiboot-Formatsignatur. Die .set-Direktive setzt den Wert eines Zeichens auf einen Ausdruck rechts vom Komma. Die Direktive .align 4 richtet den nachfolgenden Inhalt um 4 Byte aus. Die Direktive .long speichert den Wert in vier aufeinanderfolgenden Bytes.

STACKSIZE setzen, 0x4000 # STACKSIZE = 0x4000 .lcomm Stack zuweisen, STACKSIZE # STACKSIZE-Bytes reservieren. stack bezieht sich auf die mbd range.comm, 4 # reserviert 4 Byte für die Variable mdb im COMMON-Bereich .comm magic, 4 # reserviert 4 Byte für die Magic-Variable im COMMON-Bereich

Im Gange boot grub konfiguriert den Stack nicht, und das erste, was der Kernel tun sollte, ist den Stack zu konfigurieren, dafür reservieren wir 0x4000 (16Kb) Bytes. Die .lcomm-Direktive reserviert die Anzahl der Bytes nach dem Komma im .bss-Abschnitt. Der Stack-Name ist nur in der kompilierten Datei sichtbar. Die .comm-Direktive macht dasselbe wie .lcomm, aber der Symbolname wird global deklariert. Das bedeutet, dass wir sie verwenden können, indem wir die folgende Zeile in den C-Code schreiben.
extern int magie

Und nun der letzte Teil:

Loader: movl $ (stack + STACKSIZE),% esp # initialize stack movl% eax, magic # write% eax to magic movl% ebx, mbd # write% ebx to mbd call main # call main function cli # deaktivieren Interrupts von Hardware-Hang : hlt # Prozessor stoppen, bis Interrupt auftritt jmp hang # jump to hang tag

Die erste Anweisung besteht darin, den Wert oben auf dem Stapel im Register % esp zu speichern. Wenn der Stack nach unten wächst, speichert % esp die Adresse des Endes des dem Stack zugewiesenen Bereichs. Die nächsten beiden Befehle speichern in den zuvor reservierten Bereichen von 4 Bytes die Werte, die Grub in die % eax,% ebx-Register übergibt. Dann wird die main-Funktion aufgerufen, die bereits in C geschrieben ist. Wenn diese Prozedur zurückkehrt, geht der Prozessor in eine Schleife.

Schritt 2. Bereiten Sie zusätzlichen Code für das Programm vor (Systembibliothek):

Da das gesamte Programm von Grund auf neu geschrieben wird, muss die printf-Funktion von Grund auf neu geschrieben werden. Dazu müssen Sie mehrere Dateien vorbereiten.
Lassen Sie uns einen allgemeinen und einen Include-Ordner erstellen:

Mkdir allgemeines mkdir enthalten

Erstellen wir eine Datei commonprintf.c, die die Implementierung der bekannten printf-Funktion enthält. Die gesamte Datei kann dem Projekt www.bitvisor.org/ entnommen werden. Der Pfad zur Datei in den Bitvisor-Quellen: core / printf.c. In der von Bitvisor kopierten printf.c-Datei zur Verwendung im Zielprogramm müssen Sie die Zeilen ersetzen:

#include "initfunc.h" #include "printf.h" #include "putchar.h" #include "spinlock.h"

pro Zeile:

#include "types.h" #include "stdarg.h" #include "screen.h"

Entfernen Sie dann die Funktion printf_init_global und alle ihre Referenzen in dieser Datei:

Statisch void printf_init_global (void) (spinlock_init (& printf_lock);) INITFUNC ("global0", printf_init_global);

Entfernen Sie dann die Variable printf_lock und alle Verweise darauf in dieser Datei:

Statisches spinlock_t printf_lock; … Spinlock_lock (& ​​printf_lock); ... spinlock_unlock (& ​​printf_lock);

Die printf-Funktion verwendet die putchar-Funktion, die ebenfalls geschrieben werden muss. Erstellen Sie dazu eine Datei commonscreen.c mit folgendem Inhalt:

#include "types.h" #define GREEN 0x2 #define MAX_COL 80 // Maximale Spaltenanzahl #define MAX_ROW 25 // Maximale Zeilenanzahl #define VRAM_SIZE (MAX_COL * MAX_ROW) // Bildschirmgröße, kurz "s # define DEF_VRAM_BASE 0xb8000 // Standardbasis für Videospeicher static unsigned char curr_col = 0; static unsigned char curr_row = 0; // Zeichen an der aktuellen Bildschirmposition schreiben #define PUT (c) (((unsigned short *) (DEF_VRAM_BASE)) [ (curr_row * MAX_COL) + curr_col] = (GRÜN<< 8) | (c)) // Place a character on next screen position static void cons_putc(int c) { switch (c) { case "t": do { cons_putc(" "); } while ((curr_col % 8) != 0); break; case "r": curr_col = 0; break; case "n": curr_row += 1; if (curr_row >= MAX_ROW) (curr_row = 0;) Pause; Fall "b": if (curr_col> 0) (curr_col - = 1; PUT ("");) break; Vorgabe: PUT (c); curr_col + = 1; if (curr_col> = MAX_COL) (curr_col = 0; curr_row + = 1; if (curr_row> = MAX_ROW) (curr_row = 0;))); ) void putchar (int c) (if (c == "n") cons_putc ("r"); cons_putc (c);) void clear_screen (void) (curr_col = 0; curr_row = 0; int i; for (i = 0; ich< VRAM_SIZE; i++) cons_putc(" "); curr_col = 0; curr_row = 0; }

Der obige Code enthält eine einfache Logik zum Drucken von Zeichen auf dem Bildschirm im Textmodus. In diesem Modus werden zwei Bytes verwendet, um ein Zeichen (eins mit dem Zeichencode, das andere mit seinen Attributen) direkt in den sofort auf dem Bildschirm angezeigten Videospeicher zu schreiben, beginnend mit der Adresse 0xB8000. Die Bildschirmauflösung beträgt 80x25 Zeichen. Der Direktdruck eines Symbols erfolgt über das PUT-Makro.
Jetzt fehlen nur noch ein paar Header-Dateien:
1. Die Datei includescreen.h. Deklariert die putchar-Funktion, die in der printf-Funktion verwendet wird. Dateiinhalt:

#ifndef _SCREEN_H #define _SCREEN_H void clear_screen (void); void putchar (int c); #endif

2. Datei includeprintf.h. Deklariert die printf-Funktion, die in main verwendet wird. Dateiinhalt:

#ifndef _PRINTF_H #define _PRINTF_H int printf (const char * Format, ...); #endif

3. Die Datei includetdarg.h. Deklariert Funktionen zum Durchlaufen von Argumenten, deren Anzahl im Voraus nicht bekannt ist. Die gesamte Datei stammt aus dem Projekt www.bitvisor.org/. Dateipfad im Bitvisor-Projektcode: includecorestdarg.h.
4. Datei includetypes.h. Deklariert NULL und size_t. Dateiinhalt:

#ifndef _TYPES_H #define _TYPES_H #define NULL 0 typedef unsigned int size_t; #endif

Somit enthalten die Ordner include und common den minimalen Systembibliothekscode, den jedes Programm benötigt.

Schritt 3. Erstellen Sie ein Skript für den Linker:

Erstellen Sie eine Datei linker.ld, die vom Linker verwendet wird, um die Zielprogrammdatei (kernel.bin) zu generieren. Die Datei sollte Folgendes enthalten:

EINTRAG (Lader) LMA = 0x00100000; SECTIONS (. = LMA; .multiboot ALIGN (0x1000): (loader.o (.text)) .text ALIGN (0x1000): (* (. Text)) .rodata ALIGN (0x1000): (* (. Rodata *) ) .data ALIGN (0x1000): (* (. data)) .bss: (* (COMMON) * (. bss)) / DISCARD /: (* (. Kommentar)))

Mit der eingebauten Funktion ENTRY() können wir den Einstiegspunkt für unseren Kernel setzen. An diese Adresse überträgt Grub die Kontrolle, nachdem der Kernel geladen wurde. Der Linker verwendet dieses Skript, um eine ELF-Binärdatei zu erstellen. Eine ELF-Datei besteht aus einer Reihe von Segmenten und Abschnitten. Die Liste der Segmente ist in der Kopftabelle Programm enthalten, die Liste der Abschnitte befindet sich in der Kopftabelle Abschnitt. Der Linker arbeitet mit Abschnitten, der Image Loader (in unserem Fall GRUB) mit Segmenten.


Wie Sie in der Abbildung sehen können, bestehen Segmente aus Abschnitten. Eines der Felder, die den Abschnitt beschreiben, ist die virtuelle Adresse, an der sich der Abschnitt zum Zeitpunkt der Ausführung befinden soll. Tatsächlich hat ein Segment 2 Felder, die seinen Standort beschreiben: die virtuelle Adresse des Segments und die physikalische Adresse des Segments. Die virtuelle Adresse des Segments ist die virtuelle Adresse des ersten Bytes des Segments zum Zeitpunkt der Codeausführung, die physikalische Adresse des Segments ist die physikalische Adresse, an der das Segment geladen werden soll. Bei Anwendungsprogrammen sind diese Adressen immer gleich. Grub lädt Bildsegmente an ihrer physischen Adresse. Da Grub kein Paging konfiguriert, muss die virtuelle Adresse des Segments mit seiner physischen Adresse übereinstimmen, da in unserem Programm virtueller Speicher auch nicht konfigurierbar.

LMA;

Dieser Ausdruck teilt dem Linker mit, dass alle nachfolgenden Abschnitte nach der LMA-Adresse stehen.

AUSRICHTEN (0x1000)

Die obige Anweisung bedeutet, dass der Abschnitt 0x1000 Byte ausgerichtet ist.

Multiboot ALIGN (0x1000): (loader.o (.text))

Ein separater Multiboot-Abschnitt, der den .text-Abschnitt aus der Datei loader.o enthält, wird erstellt, um sicherzustellen, dass die Multiboot-Formatsignatur in die ersten 8 KB des Kernel-Images gelangt.

Bss: (* (ALLGEMEIN) * (. Bss))

* (COMMON) ist der Bereich, in dem Speicher durch die Befehle .comm und.lcomm reserviert wird. Wir platzieren es in der .bss-Sektion.

/ VERWERFEN /: (* (. Kommentar))

Alle als DISCARD markierten Abschnitte werden aus dem Bild entfernt. In diesem Fall löschen wir den Abschnitt.comment, der Informationen über die Version des Linkers enthält.

Lassen Sie uns nun den Code mit den folgenden Befehlen in eine Binärdatei kompilieren:

Als -o loader.o loader.s gcc -Iinclude -Wall -fno-builtin -nostdinc -nostdlib -o kernel.o -c kernel.c gcc -Iinclude -Wall -fno-builtin -nostdinc -nostdlib -o printf.o -c common / printf.c gcc -Iinclude -Wall -fno-builtin -nostdinc -nostdlib -o screen.o -c common /screen.c ld -T linker.ld -o kernel.bin kernel.o screen.o printf .o Lader.o

Sehen wir uns mit objdump an, wie das Kernel-Image nach dem Linken aussieht:

Objdump -ph ./kernel.bin



Wie Sie sehen können, sind die Abschnitte im Bild die gleichen wie die im Linker-Skript beschriebenen. Der Linker hat aus den beschriebenen Abschnitten 3 Segmente gebildet. Das erste Segment enthält die Abschnitte multiboot, .text, .rodata und hat eine virtuelle und physikalische Adresse von 0x00100000. Das zweite Segment enthält die Abschnitte .data und .bss und befindet sich unter 0x00104000. Sie können diese Datei also mit Grub herunterladen.

Schritt 4. Bereiten Sie den Grub-Bootloader vor:
Grub-Ordner erstellen:

Mkdir grub

Kopieren Sie mehrere Grub-Dateien in diesen Ordner, die notwendig sind, um es auf dem Image zu installieren (die folgenden Dateien sind vorhanden, wenn Grub auf dem System installiert ist). Dazu müssen Sie die folgenden Befehle ausführen:

Cp / usr / lib / grub / i386-pc / stage1 ./grub/ cp / usr / lib / grub / i386-pc / stage2 ./grub/ cp / usr / lib / grub / i386-pc / fat_stage1_5 ./grub /

Erstellen Sie eine Datei grub/menu.lst mit folgendem Inhalt:

Timeout 3 Standard 0 Titel mini_os root (hd0,0) Kernel /kernel.bin

Schritt 5. Automatisieren und erstellen Sie ein bootfähiges Image:

Um den Build-Prozess zu automatisieren, verwenden wir das Dienstprogramm make. Dazu erstellen wir ein Makefile, das Quellcode kompiliert, einen Kernel erstellt und ein Boot-Image erstellt. Das Makefile sollte folgenden Inhalt haben:

CC = gcc CFLAGS = -Wall -fno-builtin -nostdinc -nostdlib LD = ld OBJFILES = loader.o common / printf.o common / screen.o kernel.o image: @echo "HDD.img erstellen ..." @ dd if = / dev / zero of =. / hdd.img bs = 512 count = 16065 1> / dev / null 2> & 1 @echo "Bootfähige erste FAT32-Partition erstellen ..." @losetup / dev / loop1 ./ hdd .img @ (echo c; echo u; echo n; echo p; echo 1; echo; echo; echo a; echo 1; echo t; echo c; echo w;) | fdisk / dev / loop1 1> / dev / null 2> & 1 || true @echo "Einhängen der Partition nach /dev/loop2 ..." @losetup /dev/loop2 ./hdd.img --offset `echo` fdisk -lu /dev/loop1 | sed -n 10p | awk "(Drucke $$ 3)" `* 512 | bc` --sizelimit `echo` fdisk -lu / dev / loop1 | sed -n 10p | awk "($$ 4) drucken" `* 512 | bc` @losetup -d / dev / loop1 @echo "Partition formatieren ..." @mkdosfs / dev / loop2 @echo "Kernel- und Grub-Dateien auf Partition kopieren ..." @mkdir -p tempdir @mount / dev / loop2 tempdir @mkdir tempdir / boot @cp -r grub tempdir / boot / @cp kernel.bin tempdir / @sleep 1 @umount / dev / loop2 @rm -r tempdir @losetup -d / dev / loop2 @echo "Installation von GRUB. .. "@echo" device (hd0) hdd.img n root (hd0,0) n setup (hd0) n quitn "| grub --batch 1> / dev / null @echo "Fertig!" all: kernel.bin rebuild: clean all .s.o: as -o [E-Mail geschützt] $< .c.o: $(CC) -Iinclude $(CFLAGS) -o [E-Mail geschützt]-c $< kernel.bin: $(OBJFILES) $(LD) -T linker.ld -o [E-Mail geschützt]$ ^ clean: rm -f $ (OBJFILES) hdd.img kernel.bin

Die Datei deklariert zwei Hauptziele: all - kompiliert den Kernel und Image - das eine Bootdiskette erstellt. Das all-Ziel enthält, wie das übliche Makefile, die Unterziele .so und .co, die *.s- und *.c-Dateien in Objektdateien (*.o) kompilieren, sowie ein Ziel zum Generieren von kernel.bin, das aufruft den Linker mit dem zuvor erstellten Skript. Diese Ziele führen genau die gleichen Befehle wie in Schritt 3 angegeben aus.
Von größtem Interesse ist hier die Kreation Boot-Image hdd.img (Zielbild). Betrachten wir in Etappen, wie dies geschieht.

Dd if = / dev / null von =. / Hdd.img bs = 512 count = 16065 1> / dev / null 2> & 1

Dieser Befehl erstellt ein Image, mit dem weitergearbeitet wird. Die Anzahl der Sektoren wurde nicht zufällig gewählt: 16065 = 255 * 63. Standardmäßig arbeitet fdsik mit der Platte, als ob sie eine CHS-Geometrie hätte, in der Header (H) = 255, Sektoren (S) = 63 und Zylinder © abhängig sind von der Festplattengröße... Somit beträgt die minimale Festplattengröße, mit der das Dienstprogramm fdsik arbeiten kann, ohne die Standardgeometrie zu ändern, 512 * 255 * 63 * 1 = 8225280 Byte, wobei 512 die Sektorgröße und 1 die Anzahl der Zylinder ist.
Als nächstes wird eine Partitionstabelle erstellt:

Losetup / dev / loop1 ./hdd.img (echo c; echo u; echo n; echo p; echo 1; echo; echo; echo a; echo 1; echo t; echo c; echo w;) | fdisk / dev / loop1 1> / dev / null 2> & 1 || wahr

Der erste Befehl mountet die Datei hdd.img auf das Blockgerät /dev/loop1, wodurch die Datei wie ein Gerät behandelt werden kann. Der zweite Befehl erstellt eine Partitionstabelle auf dem Gerät / dev / loop1, die 1 primäre enthält Bootpartition Festplatte, die die gesamte Festplatte belegt und mit dem FAT32-Dateisystem gekennzeichnet ist.
Dann formatieren wir den erstellten Abschnitt. Dazu müssen Sie es als Blockgerät mounten und formatieren.

Losetup / dev / loop2 ./hdd.img --offset `echo` fdisk -lu / dev / loop1 | sed -n 10p | awk "(Drucke $$ 3)" `* 512 | bc` --sizelimit `echo` fdisk -lu / dev / loop1 | sed -n 10p | awk "($$ 4) drucken" `* 512 | bc`losetup -d / dev / loop1

Der erste Befehl mountet die zuvor erstellte Partition auf dem /dev/loop2-Gerät. Die Option –offset gibt den Anfang des Abschnitts und –sizelimit das Ende des Abschnitts an. Beide Parameter werden mit dem Befehl fdisk abgerufen.

Mkdosfs / dev / loop2

Das Dienstprogramm mkdosfs formatiert die Partition in Dateisystem FAT32.
Um den Kernel direkt zu bauen, werden die zuvor in der klassischen Makefile-Syntax diskutierten Befehle verwendet.
Sehen wir uns nun an, wie Sie GRUB auf einer Partition installieren:

Mkdir -p tempdir # erstellt ein temporäres Verzeichnis mount / dev / loop2 tempdir # mountet die Partition im mkdir-Verzeichnis tempdir / boot # erstellt ein / boot-Verzeichnis auf der cp-Partition -r grub tempdir / boot / # kopiert den grub-Ordner nach / boot cp kernel.bin tempdir / # kopiert den Kernel in das Stammverzeichnis der Partition sleep 1 # warte auf Ubuntu umount / dev / loop2 # unmounte den temporären Ordner rm -r tempdir # lösche den temporären Ordner losetup -d / dev / loop2 # die Partition aushängen

Nachdem Sie die obigen Befehle ausgeführt haben, ist das Image bereit für die Installation von GRUB. Der folgende Befehl installiert GRUB in den MBR des Festplatten-Image hdd.img.

Echo "device (hd0) hdd.img n root (hd0,0) n setup (hd0) n quitn" | grub --batch 1> / dev / null

Alles ist bereit zum Testen!

Schritt 6. Starten:

Verwenden Sie zum Kompilieren den Befehl:

Mache alles

Danach sollte die Datei kernel.bin erscheinen.
Um ein bootfähiges Disk-Image zu erstellen, verwenden Sie den Befehl:

Sudo Bild erstellen

Als Ergebnis sollte die Datei hdd.img erscheinen.
Jetzt können Sie vom Festplatten-Image hdd.img booten. Sie können dies mit dem folgenden Befehl überprüfen:

Qemu -hda hdd.img -m 32

Qemu-system-i386 -hda hdd.img




Um auf einem echten Computer zu überprüfen, müssen Sie dieses Image auf ein Flash-Laufwerk kopieren und von diesem booten. Zum Beispiel mit folgendem Befehl:

Sudo dd if =. / Hdd.img of = / dev / sdb

Zusammenfassend können wir sagen, dass als Ergebnis der durchgeführten Aktionen eine Reihe von Quellen und Skripten erhalten wird, mit denen Sie verschiedene Experimente im Bereich der Systemprogrammierung durchführen können. Der erste Schritt zur Erstellung von Systemsoftware wie Hypervisoren und Betriebssystemen.

Das Wichtigste wurde nicht ausführlich genug beschrieben: Wie läuft dieser Code auf echter Hardware ab? Wie erstelle ich meine eigene bootfähige Disk? In diesem Artikel werden wir all diese Fragen im Detail beantworten (einige dieser Fragen wurden im vorherigen Artikel behandelt, aber zur besseren Lesbarkeit erlauben wir uns eine kleine Vervielfältigung des Materials).

Im Internet gibt es eine Vielzahl von Beschreibungen und Tutorials, wie man sein eigenes Mini-OS schreibt, es gibt sogar Hunderte von vorgefertigten kleinen Hobby-Betriebssystemen. Eine der wertvollsten Ressourcen zu diesem Thema, die ich hervorheben möchte, ist das Portal osdev.org. Um den vorherigen Artikel über PCI (und die Möglichkeit, nachfolgende Artikel über die verschiedenen Funktionen, die in jedem modernen Betriebssystem vorhanden sind) zu schreiben, zu ergänzen, beschreiben wir Schritt-für-Schritt-Anleitungen zum Erstellen einer bootfähigen Festplatte mit einem vertrauten Programm in C. Wir Ich habe versucht, so detailliert wie möglich zu schreiben, um alles selbst herauszufinden.

Das Ziel also: Erstellen Sie mit möglichst wenig Aufwand Ihren eigenen bootfähigen USB-Stick, der einfach das klassische "Hello World" auf den Computerbildschirm druckt.

Um genauer zu sein, müssen wir in den geschützten Modus mit deaktiviertem Paging und Interrupts "kommen" - den einfachsten Modus des Prozessors mit dem üblichen Verhalten für ein einfaches Konsolenprogramm. Der klügste Weg, dies zu erreichen, besteht darin, einen Multiboot-Kernel zu erstellen und ihn mit dem beliebten Grub-Bootloader zu booten. Eine Alternative zu dieser Lösung besteht darin, einen eigenen Volume Boot Record (VBR) zu schreiben, der den geschriebenen eigenen Loader (Loader) laden würde. Zumindest ein anständiger Bootloader sollte in der Lage sein, mit einer Festplatte, einem Dateisystem und dem Parsen von Elf-Images zu arbeiten. Das bedeutet, dass Sie viel Assemblercode und viel C-Code schreiben müssen, kurz gesagt, es ist einfacher, Grub zu verwenden, das bereits alles weiß, was Sie tun müssen.

Zu Beginn erfordern weitere Aktionen einen bestimmten Satz von Compilern und Dienstprogrammen. Am einfachsten ist es, eine Art Linux (z. B. Ubuntu) zu verwenden, da es bereits alles enthält, was Sie zum Erstellen eines bootfähigen USB-Flash-Laufwerks benötigen. Wenn Sie es gewohnt sind, unter Windows zu arbeiten, können Sie eine virtuelle Linux-Maschine einrichten (mit Virtual Box oder VMware Workstation).

Wenn Sie Linux Ubuntu verwenden, müssen Sie zunächst mehrere Dienstprogramme installieren:
1. Grub. Verwenden Sie dazu den Befehl:
sudo apt-get install grub

2. Qemu. Es wird benötigt, um alles schnell zu machen, dafür ist der Befehl ähnlich:
sudo apt-get install qemu

Unser Plan sieht jetzt so aus:
1.Erstellen Sie ein C-Programm, das eine Zeichenfolge auf dem Bildschirm ausgibt.
2. Erstellen Sie daraus ein Image (kernel.bin) im Miniboot-Format, damit es zum Booten mit GRUB verfügbar ist.
3. Erstellen Sie eine bootfähige Disk-Image-Datei und formatieren Sie sie.
4. Installieren Sie Grub auf diesem Image.
5. Kopieren Sie das erstellte Programm (kernel.bin) auf die Diskette.
6. Schreiben Sie das Image auf ein physisches Medium oder führen Sie es in qemu aus.

Und der Systemstartprozess:

Dazu müssen Sie mehrere Dateien und Verzeichnisse erstellen:

Schritt 1. Generieren des Zielprogramm-(Kernel-)Codes:

Erstellen Sie eine Datei kernel.c, die den folgenden Code enthält, um eine Meldung auf dem Bildschirm zu drucken:

#include "printf.h" #include "screen.h" #include "types.h" void main (void) (clear_screen (); printf ("\ n >>> Hallo Welt! \ n");)

Hier ist alles vertraut und einfach. Das Hinzufügen der Funktionen printf und clear_screen wird später besprochen. In der Zwischenzeit müssen wir diesen Code mit allem Notwendigen ergänzen, damit er von Grub geladen werden kann.
Damit der Kernel im Multiboot-Format vorliegt, wird in den ersten 8 Kilobyte des Kernel-Images die folgende Struktur benötigt:

Wenn alle angegebenen Bedingungen erfüllt sind, übergibt Grub einen Zeiger auf die Multiboot-Informationsstruktur und den Wert 0x1BADB002 durch die Register % eax bzw. % ebx. Die Multiboot-Informationsstruktur enthält verschiedene Informationen, einschließlich einer Liste der geladenen Module und ihrer Position, die möglicherweise zum weiteren Booten des Systems benötigt werden.
Damit die Datei mit dem Programm die notwendigen Signaturen enthält, erstellen wir eine Datei loader.s mit folgendem Inhalt:

Text .global loader # Einstiegspunkt für Linker sichtbar machen # Multiboot-Header einrichten - Details siehe GRUB-Dokumentation .set FLAGS, 0x0 # Dies ist das Multiboot-"Flag"-Feld .set MAGIC, 0x1BADB002 # "magische Nummer" lässt den Bootloader finden der Header .set CHECKSUM, - (MAGIC + FLAGS) # Prüfsumme erforderlich .align 4 .long MAGIC .long FLAGS .long CHECKSUM # anfänglichen Kernel-Stack-Speicherplatz reservieren .set STACKSIZE, 0x4000 # dh 16k. .lcomm Stack, STACKSIZE # 16k Stack reservieren .comm mbd, 4 # wir werden dies in kmain .comm magic verwenden, 4 # wir werden dies in kmain loader verwenden: movl $ (stack + STACKSIZE),% esp # den Stack einrichten movl% eax, magic # Multiboot magische Zahl movl% ebx, mbd # Multiboot-Datenstruktur call main # call C-Code cli hang: hlt # halt machine sollte der Kernel jmp hang zurückgeben

Schauen wir uns den Code genauer an. Dieser Code stammt fast unverändert aus wiki.osdev.org/Bare_Bones. Da gcc für die Kompilierung verwendet wird, wird die GAS-Syntax verwendet. Schauen wir uns genauer an, was dieser Code macht.
.Text
Der gesamte nachfolgende Code fällt in den ausführbaren Abschnitt .text.
.globaler Lader
Wir deklarieren das Loader-Symbol für den Linker sichtbar. Dies ist erforderlich, da der Linker den Loader als Einstiegspunkt verwendet.
.set FLAGS, 0x0 # zuweisen FLAGS = 0x0 .set MAGIC, 0x1BADB002 # zuweisen MAGIC = 0x1BADB002 .set CHECKSUM, - (MAGIC + FLAGS) # zuweisen CHECKSUM = - (MAGIC + FLAGS) .align 4 # nachfolgende Daten um 4 Bytes ausrichten .long MAGIC # Platziere den MAGIC-Wert an der aktuellen Adresse .long FLAGS # Platziere den FLAGS-Wert an der aktuellen Adresse .long CHECKSUM # Platziere den CHECKSUM-Wert an der aktuellen Adresse
Dieser Code generiert eine Multiboot-Formatsignatur. Die .set-Direktive setzt den Wert eines Zeichens auf einen Ausdruck rechts vom Komma. Die Direktive .align 4 richtet den nachfolgenden Inhalt um 4 Byte aus. Die Direktive .long speichert den Wert in vier aufeinanderfolgenden Bytes.
.set STACKSIZE, 0x4000 # STACKSIZE = 0x4000 zuweisen .lcomm Stack, STACKSIZE # STACKSIZE Bytes reservieren. stack bezieht sich auf die mbd range.comm, 4 # reserviert 4 Byte für die Variable mdb im COMMON-Bereich .comm magic, 4 # reserviert 4 Byte für die Magic-Variable im COMMON-Bereich
Während des Bootvorgangs konfiguriert Grub den Stack nicht, und das erste, was der Kernel tun muss, ist den Stack zu konfigurieren, dafür reservieren wir 0x4000 (16Kb) Bytes. Die .lcomm-Direktive reserviert die Anzahl der Bytes nach dem Komma im .bss-Abschnitt. Der Stack-Name ist nur in der kompilierten Datei sichtbar. Die .comm-Direktive macht dasselbe wie .lcomm, aber der Symbolname wird global deklariert. Das bedeutet, dass wir sie verwenden können, indem wir die folgende Zeile in den C-Code schreiben.
extern int magie

Und nun der letzte Teil:
loader: movl $ (stack + STACKSIZE),% esp # initialize stack movl% eax, magic # write% eax to magic movl% ebx, mbd # write% ebx to mbd call main # call main function cli # deaktivieren Interrupts von Hardware-Hang : hlt # Prozessor stoppen, bis Interrupt auftritt jmp hang # jump to hang tag

Die erste Anweisung besteht darin, den Wert oben auf dem Stapel im Register % esp zu speichern. Wenn der Stack nach unten wächst, speichert % esp die Adresse des Endes des dem Stack zugewiesenen Bereichs. Die nächsten beiden Befehle speichern in den zuvor reservierten Bereichen von 4 Bytes die Werte, die Grub in die % eax,% ebx-Register übergibt. Dann wird die main-Funktion aufgerufen, die bereits in C geschrieben ist. Wenn diese Prozedur zurückkehrt, geht der Prozessor in eine Schleife.

Schritt 2. Bereiten Sie zusätzlichen Code für das Programm vor (Systembibliothek):

Da das gesamte Programm von Grund auf neu geschrieben wird, muss die printf-Funktion von Grund auf neu geschrieben werden. Dazu müssen Sie mehrere Dateien vorbereiten.
Lassen Sie uns einen allgemeinen und einen Include-Ordner erstellen:

Mkdir allgemeines mkdir enthalten

Erstellen wir eine Datei common \ printf.c, die die Implementierung der bekannten printf-Funktion enthält. Diese Datei kann vollständig dem Projekt www.bitvisor.org entnommen werden. Der Pfad zur Datei in den Bitvisor-Quellen: core / printf.c. In der von Bitvisor kopierten printf.c-Datei zur Verwendung im Zielprogramm müssen Sie die Zeilen ersetzen:

#include "initfunc.h" #include "printf.h" #include "putchar.h" #include "spinlock.h"
pro Zeile:
#include "types.h" #include "stdarg.h" #include "screen.h"

Entfernen Sie dann die Funktion printf_init_global und alle ihre Referenzen in dieser Datei:

Statisch void printf_init_global (void) (spinlock_init (& printf_lock);) INITFUNC ("global0", printf_init_global);

Entfernen Sie dann die Variable printf_lock und alle Verweise darauf in dieser Datei:
statisches spinlock_t printf_lock; … Spinlock_lock (& ​​printf_lock); ... spinlock_unlock (& ​​printf_lock);

Die printf-Funktion verwendet die putchar-Funktion, die ebenfalls geschrieben werden muss. Erstellen Sie dazu eine gemeinsame Datei \ screen.c mit folgendem Inhalt:
#include "types.h" #define GREEN 0x2 #define MAX_COL 80 // Maximale Spaltenanzahl #define MAX_ROW 25 // Maximale Zeilenanzahl #define VRAM_SIZE (MAX_COL * MAX_ROW) // Bildschirmgröße, kurz "s # define DEF_VRAM_BASE 0xb8000 // Standardbasis für Videospeicher static unsigned char curr_col = 0; static unsigned char curr_row = 0; // Zeichen an der aktuellen Bildschirmposition schreiben #define PUT (c) (((unsigned short *) (DEF_VRAM_BASE)) \ [(curr_row * MAX_COL) + curr_col] = (GRÜN<< 8) | (c)) // Place a character on next screen position static void cons_putc(int c) { switch (c) { case "\t": do { cons_putc(" "); } while ((curr_col % 8) != 0); break; case "\r": curr_col = 0; break; case "\n": curr_row += 1; if (curr_row >= MAX_ROW) (curr_row = 0;) Pause; case "\ b": if (curr_col> 0) (curr_col - = 1; PUT ("");) break; Vorgabe: PUT (c); curr_col + = 1; if (curr_col> = MAX_COL) (curr_col = 0; curr_row + = 1; if (curr_row> = MAX_ROW) (curr_row = 0;))); ) void putchar (int c) (if (c == "\ n") cons_putc ("\ r"); cons_putc (c);) void clear_screen (void) (curr_col = 0; curr_row = 0; int i; for (i = 0; ich< VRAM_SIZE; i++) cons_putc(" "); curr_col = 0; curr_row = 0; }

Der obige Code enthält eine einfache Logik zum Drucken von Zeichen auf dem Bildschirm im Textmodus. In diesem Modus werden zwei Bytes verwendet, um ein Zeichen (eins mit dem Zeichencode, das andere mit seinen Attributen) direkt in den sofort auf dem Bildschirm angezeigten Videospeicher zu schreiben, beginnend mit der Adresse 0xB8000. Die Bildschirmauflösung beträgt 80x25 Zeichen. Der Direktdruck eines Symbols erfolgt über das PUT-Makro.
Jetzt fehlen nur noch ein paar Header-Dateien:
1. Datei enthalten \ screen.h. Deklariert die putchar-Funktion, die in der printf-Funktion verwendet wird. Dateiinhalt:
#ifndef _SCREEN_H #define _SCREEN_H void clear_screen (void); void putchar (int c); #endif

2. Datei include \ printf.h. Deklariert die printf-Funktion, die in main verwendet wird. Dateiinhalt:
#ifndef _PRINTF_H #define _PRINTF_H int printf (const char * Format, ...); #endif

3. Datei include \ stdarg.h. Deklariert Funktionen zum Durchlaufen von Argumenten, deren Anzahl im Voraus nicht bekannt ist. Die gesamte Datei stammt aus dem Projekt www.bitvisor.org. Der Pfad zur Datei im Bitvisor-Projektcode lautet include\core\stdarg.h.
4. Datei include \types.h. Deklariert NULL und size_t. Dateiinhalt:
#ifndef _TYPES_H #define _TYPES_H #define NULL 0 typedef unsigned int size_t; #endif
Somit enthalten die Ordner include und common den minimalen Systembibliothekscode, den jedes Programm benötigt.

Schritt 3. Erstellen Sie ein Skript für den Linker:

Erstellen Sie eine Datei linker.ld, die vom Linker verwendet wird, um die Zielprogrammdatei (kernel.bin) zu generieren. Die Datei sollte Folgendes enthalten:

EINTRAG (Lader) LMA = 0x00100000; SECTIONS (. = LMA; .multiboot ALIGN (0x1000): (loader.o (.text)) .text ALIGN (0x1000): (* (. Text)) .rodata ALIGN (0x1000): (* (. Rodata *) ) .data ALIGN (0x1000): (* (. data)) .bss: (* (COMMON) * (. bss)) / DISCARD /: (* (. Kommentar)))

Mit der eingebauten Funktion ENTRY() können wir den Einstiegspunkt für unseren Kernel setzen. An diese Adresse überträgt Grub die Kontrolle, nachdem der Kernel geladen wurde. Der Linker verwendet dieses Skript, um eine ELF-Binärdatei zu erstellen. Eine ELF-Datei besteht aus einer Reihe von Segmenten und Abschnitten. Die Liste der Segmente ist in der Kopftabelle Programm enthalten, die Liste der Abschnitte befindet sich in der Kopftabelle Abschnitt. Der Linker arbeitet mit Abschnitten, der Image Loader (in unserem Fall GRUB) mit Segmenten.


Wie Sie in der Abbildung sehen können, bestehen Segmente aus Abschnitten. Eines der Felder, die den Abschnitt beschreiben, ist die virtuelle Adresse, an der sich der Abschnitt zum Zeitpunkt der Ausführung befinden soll. Tatsächlich hat ein Segment 2 Felder, die seinen Standort beschreiben: die virtuelle Adresse des Segments und die physikalische Adresse des Segments. Die virtuelle Adresse des Segments ist die virtuelle Adresse des ersten Bytes des Segments zum Zeitpunkt der Codeausführung, die physikalische Adresse des Segments ist die physikalische Adresse, an der das Segment geladen werden soll. Bei Anwendungsprogrammen sind diese Adressen immer gleich. Grub lädt Bildsegmente an ihrer physischen Adresse. Da Grub kein Paging konfiguriert, muss die virtuelle Adresse des Segments mit seiner physikalischen Adresse übereinstimmen, da in unserem Programm auch kein virtueller Speicher konfiguriert ist.

ABSCHNITTE
Zeigt an, dass die Abschnitte im Folgenden beschrieben werden.
... = LMA;
Dieser Ausdruck teilt dem Linker mit, dass alle nachfolgenden Abschnitte nach der LMA-Adresse stehen.
AUSRICHTEN (0x1000)
Die obige Anweisung bedeutet, dass der Abschnitt 0x1000 Byte ausgerichtet ist.
.multiboot ALIGN (0x1000): (loader.o (.text))
Ein separater Multiboot-Abschnitt, der den .text-Abschnitt aus der Datei loader.o enthält, wird erstellt, um sicherzustellen, dass die Multiboot-Formatsignatur in die ersten 8 KB des Kernel-Images gelangt.
.bss: (* (ALLGEMEIN) * (.bss))
* (COMMON) ist der Bereich, in dem Speicher durch die Befehle .comm und.lcomm reserviert wird. Wir platzieren es in der .bss-Sektion.
/ VERWERFEN /: (* (. Kommentar))
Alle als DISCARD markierten Abschnitte werden aus dem Bild entfernt. In diesem Fall löschen wir den Abschnitt.comment, der Informationen über die Version des Linkers enthält.

Lassen Sie uns nun den Code mit den folgenden Befehlen in eine Binärdatei kompilieren:
as -o loader.o loader.s gcc -Iinclude -Wall -fno-builtin -nostdinc -nostdlib -o kernel.o -c kernel.c gcc -Iinclude -Wall -fno-builtin -nostdinc -nostdlib -o printf.o -c common / printf.c gcc -Iinclude -Wall -fno-builtin -nostdinc -nostdlib -o screen.o -c common /screen.c ld -T linker.ld -o kernel.bin kernel.o screen.o printf .o Lader.o
Sehen wir uns mit objdump an, wie das Kernel-Image nach dem Linken aussieht:
objdump -ph ./kernel.bin


Wie Sie sehen können, sind die Abschnitte im Bild die gleichen wie die im Linker-Skript beschriebenen. Der Linker hat aus den beschriebenen Abschnitten 3 Segmente gebildet. Das erste Segment enthält die Abschnitte multiboot, .text, .rodata und hat eine virtuelle und physikalische Adresse von 0x00100000. Das zweite Segment enthält die Abschnitte .data und .bss und befindet sich unter 0x00104000. Sie können diese Datei also mit Grub herunterladen.

Schritt 4. Bereiten Sie den Grub-Bootloader vor:
Grub-Ordner erstellen:
mkdir grub

Kopieren Sie mehrere Grub-Dateien in diesen Ordner, die notwendig sind, um es auf dem Image zu installieren (die folgenden Dateien sind vorhanden, wenn Grub auf dem System installiert ist). Dazu müssen Sie die folgenden Befehle ausführen:
cp / usr / lib / grub / i386-pc / stage1 ./grub/ cp / usr / lib / grub / i386-pc / stage2 ./grub/ cp / usr / lib / grub / i386-pc / fat_stage1_5 ./grub /

Erstellen Sie eine Datei grub/menu.lst mit folgendem Inhalt:
timeout 3 default 0 title mini_os root (hd0,0) kernel /kernel.bin

Schritt 5. Automatisieren und erstellen Sie ein bootfähiges Image:

Um den Build-Prozess zu automatisieren, verwenden wir das Dienstprogramm make. Dazu erstellen wir ein Makefile, das Quellcode kompiliert, einen Kernel erstellt und ein Boot-Image erstellt. Das Makefile sollte folgenden Inhalt haben:

CC = gcc CFLAGS = -Wall -fno-builtin -nostdinc -nostdlib LD = ld OBJFILES = \ loader.o \ common / printf.o \ common / screen.o \ kernel.o image: @echo "Erstellen von hdd.img. .. "@dd if = / dev / zero of =. / hdd.img bs = 512 count = 16065 1> / dev / null 2> & 1 @echo" Bootfähige erste FAT32-Partition erstellen ... "@losetup / dev / loop1 ./hdd.img @ (echo c; echo u; echo n; echo p; echo 1; echo; echo; echo a; echo 1; echo t; echo c; echo w;) | fdisk / dev / loop1 1> / dev / null 2> & 1 || true @echo "Einhängen der Partition nach /dev/loop2 ..." @losetup /dev/loop2 ./hdd.img \ --offset `echo \` fdisk -lu / dev / loop1 | sed -n 10p | awk "($$ 3) drucken" \ `* 512 | bc` \ --sizelimit `echo \` fdisk -lu / dev / loop1 | sed -n 10p | awk "($$ 4) drucken" \ `* 512 | bc` @losetup -d / dev / loop1 @echo "Partition formatieren ..." @mkdosfs / dev / loop2 @echo "Kernel- und Grub-Dateien auf Partition kopieren ..." @mkdir -p tempdir @mount / dev / loop2 tempdir @mkdir tempdir / boot @cp -r grub tempdir / boot / @cp kernel.bin tempdir / @sleep 1 @umount / dev / loop2 @rm -r tempdir @losetup -d / dev / loop2 @echo "Installation von GRUB. .. "@echo" Gerät (hd0) hdd.img \ n \ root (hd0,0) \ n \ setup (hd0) \ n \ quit \ n "| grub --batch 1> / dev / null @echo "Fertig!" all: kernel.bin rebuild: clean all .s.o: as -o [E-Mail geschützt] $< .c.o: $(CC) -Iinclude $(CFLAGS) -o [E-Mail geschützt]-c $< kernel.bin: $(OBJFILES) $(LD) -T linker.ld -o [E-Mail geschützt]$ ^ clean: rm -f $ (OBJFILES) hdd.img kernel.bin

Die Datei deklariert zwei Hauptziele: all - kompiliert den Kernel und Image - das eine Bootdiskette erstellt. Das all-Ziel enthält, wie das übliche Makefile, die Unterziele .so und .co, die *.s- und *.c-Dateien in Objektdateien (*.o) kompilieren, sowie ein Ziel zum Generieren von kernel.bin, das aufruft den Linker mit dem zuvor erstellten Skript. Diese Ziele führen genau die gleichen Befehle wie in Schritt 3 angegeben aus.
Von besonderem Interesse ist hier die Erstellung des Boot-Image hdd.img (Ziel-Image). Betrachten wir in Etappen, wie dies geschieht.
dd if = / dev / null von =. / hdd.img bs = 512 count = 16065 1> / dev / null 2> & 1
Dieser Befehl erstellt ein Image, mit dem weitergearbeitet wird. Die Anzahl der Sektoren wurde nicht zufällig gewählt: 16065 = 255 * 63. Standardmäßig arbeitet fdsik mit der Platte, als ob sie eine CHS-Geometrie hätte, in der Header (H) = 255, Sektoren (S) = 63 und Zylinder ( C) hängt von der Festplattengröße ab. Somit beträgt die minimale Festplattengröße, mit der das Dienstprogramm fdsik arbeiten kann, ohne die Standardgeometrie zu ändern, 512 * 255 * 63 * 1 = 8225280 Byte, wobei 512 die Sektorgröße und 1 die Anzahl der Zylinder ist.
Als nächstes wird eine Partitionstabelle erstellt:
losetup / dev / loop1 ./hdd.img (echo c; echo u; echo n; echo p; echo 1; echo; echo; echo a; echo 1; echo t; echo c; echo w;) | fdisk / dev / loop1 1> / dev / null 2> & 1 || wahr
Der erste Befehl mountet die Datei hdd.img auf das Blockgerät /dev/loop1, wodurch die Datei wie ein Gerät behandelt werden kann. Der zweite Befehl erstellt eine Partitionstabelle auf dem Gerät /dev/loop1, die 1 primäre Bootpartition der Festplatte enthält, die die gesamte Festplatte belegt und mit dem FAT32-Dateisystem gekennzeichnet ist.
Dann formatieren wir den erstellten Abschnitt. Dazu müssen Sie es als Blockgerät mounten und formatieren.
losetup / dev / loop2 ./hdd.img \ --offset `echo \` fdisk -lu / dev / loop1 | sed -n 10p | awk "($$ 3) drucken" \ `* 512 | bc` \ --sizelimit `echo \` fdisk -lu / dev / loop1 | sed -n 10p | awk "($$ 4) drucken" \ `* 512 | bc`losetup -d / dev / loop1
Der erste Befehl mountet die zuvor erstellte Partition auf dem /dev/loop2-Gerät. Die Option –offset gibt den Anfang des Abschnitts und –sizelimit das Ende des Abschnitts an. Beide Parameter werden mit dem Befehl fdisk abgerufen.
mkdosfs / dev / loop2
Das Dienstprogramm mkdosfs formatiert die Partition in das FAT32-Dateisystem.
Um den Kernel direkt zu bauen, werden die zuvor in der klassischen Makefile-Syntax diskutierten Befehle verwendet.
Sehen wir uns nun an, wie Sie GRUB auf einer Partition installieren:
mkdir -p tempdir # erstellt ein temporäres Verzeichnis mount / dev / loop2 tempdir # mountet eine Partition im mkdir-Verzeichnis tempdir / boot # erstellt ein / boot-Verzeichnis auf der cp -r grub-Partition tempdir / boot / # kopiert den grub-Ordner nach / boot cp kernel.bin tempdir / # kopiert den Kernel in das Stammverzeichnis der Partition sleep 1 # warte auf Ubuntu umount / dev / loop2 # unmounte den temporären Ordner rm -r tempdir # lösche den temporären Ordner losetup -d / dev / loop2 # die Partition aushängen
Nachdem Sie die obigen Befehle ausgeführt haben, ist das Image bereit für die Installation von GRUB. Der folgende Befehl installiert GRUB in den MBR des Festplatten-Image hdd.img.
echo "device (hd0) hdd.img \ n \ root (hd0,0) \ n \ setup (hd0) \ n \ quit \ n" | grub --batch 1> / dev / null

Alles ist bereit zum Testen!

Schritt 6. Starten:

Verwenden Sie zum Kompilieren den Befehl:
mache alles
Danach sollte die Datei kernel.bin erscheinen.
Um ein bootfähiges Disk-Image zu erstellen, verwenden Sie den Befehl:
sudo bild machen
Als Ergebnis sollte die Datei hdd.img erscheinen.
Jetzt können Sie vom Festplatten-Image hdd.img booten. Sie können dies mit dem folgenden Befehl überprüfen:
qemu -hda hdd.img -m 32
oder:
qemu-system-i386 -hda hdd.img



Um auf einem echten Computer zu überprüfen, müssen Sie dieses Image auf ein Flash-Laufwerk kopieren und von diesem booten. Zum Beispiel mit folgendem Befehl:
sudo dd if =. / hdd.img of = / dev / sdb

Zusammenfassend können wir sagen, dass als Ergebnis der durchgeführten Aktionen eine Reihe von Quellen und Skripten erhalten wird, mit denen Sie verschiedene Experimente im Bereich der Systemprogrammierung durchführen können. Der erste Schritt zur Erstellung von Systemsoftware wie Hypervisoren und Betriebssystemen.

Einige Anwendungen erfordern zur Ausführung unter Windows erhöhte Rechte und müssen als Administrator ausgeführt werden. Dies zeigt die Anfrage " Benutzerkontensteuerung"(Benutzerkontensteuerung oder UAC), in dem das System Sie um Ihre Zustimmung zum Starten der Anwendung bittet.

Viele Benutzer glauben fälschlicherweise, dass die Benutzerkontensteuerung nur im Weg steht und schalten sie aus. Gleichzeitig leidet die Sicherheit des Computers stark. Zum Starten von Anwendungen ist keine Zustimmung des Benutzers mehr erforderlich, und jede Malware kann reibungslos gestartet und ausgeführt werden. Das Vorhandensein von Antivirenprogrammen kann auch keine 100%ige Computersicherheit garantieren.

In diesem Artikel zeige ich Ihnen, wie Sie das Ausführen ausgewählter Anwendungen als Administrator vereinfachen können, ohne UAC (ganz oder teilweise) zu deaktivieren und ohne die Sicherheit zu beeinträchtigen.

Es gibt mehrere Möglichkeiten, die Anwendung als Administrator auszuführen:

Als Beispiel werden wir laufen Befehlszeile(cmd) als Administrator.

Methode Nummer 1 (normal) - Start über die rechte Maustaste (UAC-Anfrage wird angezeigt)

Rechtsklick auf das Symbol gewünschte Anwendung und wählen Sie " Als Administrator ausführen":

Methode Nummer 2 - Starten Sie mit " Strg + Umschalt + Eingabetaste"(UAC-Eingabeaufforderung wird angezeigt)

Klicke auf Start, geben Sie in die Suchleiste ein der gewünschte Befehl und drücke Strg + Umschalt + Eingabetaste.

Methode Nummer 3 - Legen Sie den Start als Administrator in den Eigenschaften der Verknüpfung fest (die UAC-Anfrage wird angezeigt)

Klicken Sie mit der rechten Maustaste auf die gewünschte Verknüpfung und wählen Sie " Eigenschaften".

Gehe zum " Etikett", klicken" zusätzlich", kreuzen Sie das Kästchen an" Als Administrator ausführen":


Oder gehen Sie zum " Kompatibilität"und kreuze das Kästchen an" Führen Sie dieses Programm als Administrator aus":

Methode Nummer 4 - Vereinfachen Sie den Start für ausgewählte Anwendungen mit dem Taskplaner (UAC-Anfrage wird nicht angezeigt)

Wichtig! Diese Methode funktioniert nur für Konten, die in der Gruppe enthalten sind. Administratoren... Es wird nicht für normale Benutzer funktionieren, da ihre Rechte begrenzt sind.

Kommen wir zum interessantesten Weg. Wenn es eine Anwendung gibt, die Sie ständig ausführen und die beispielsweise von einem zuverlässigen Softwarehersteller bezogen wurde, ist dies Windows-Anwendung- Sie können den Start vereinfachen. Erstellen Sie eine Verknüpfung für das gewünschte Programm dauert nicht länger als 2 Minuten und ermöglicht es Ihnen, in Zukunft unnötige Aktionen zu vermeiden. Start Aufgabenplaner (Start---> Alle Programme ---> Standard---> Service---> Aufgabenplaner) und klicken Sie auf " Aufgabe erstellen":

Wir weisen darauf hin Name für eine neue Aufgabe und aktivieren Sie das Kontrollkästchen " Mit den höchsten Rechten ausführen":

Gehen Sie auf die Registerkarte Aktionen, Drücken Sie " Schaffen", im nächsten Fenster klicken" Überblick":

Geben Sie den Pfad zur gewünschten Anwendung an und klicken Sie auf " Offen":



Bild vergrößern

Klicken " OK":

Schließen Sie den Planer und fahren Sie mit dem Erstellen einer Verknüpfung fort.

Um eine Verknüpfung auf dem Desktop zu erstellen, klicken Sie mit der rechten Maustaste, wählen Sie " Schaffen" ---> "Etikett":


Auf dem Feld Standort der Immobilie wir stellen vor:

Schtasks / run / tn cmd_admin

wo cmd_admin- der Name der von uns erstellten Aufgabe. Wenn der Name Leerzeichen enthält, muss er in Anführungszeichen eingeschlossen werden.

Wir legen den Namen der Verknüpfung fest:



Bild vergrößern

Die Verknüpfung ist erstellt und kann verwendet werden.

Um das Symbol zu ändern - klicken Sie mit der rechten Maustaste auf die Verknüpfung, wählen Sie " Eigenschaften":

Gehe zum " Etikett"und drücke " Icon ändern":

"Überblick..."

Wir geben den Pfad zum Programm an:



Bild vergrößern

Wählen Sie das gewünschte Symbol aus und schließen Sie beide Fenster mit der " OK":

Nun erfolgt der Start der gewünschten Anwendung als Administrator durch einen Doppelklick auf die erstellte Verknüpfung, während die UAC-Eingabeaufforderung nicht angezeigt wird und die Sicherheit erhalten bleibt.

Dienstprogramm für die Automatisierung "Methode Nummer 4"

Wenn Sie Verknüpfungen für eine große Anzahl von Programmen erstellen müssen, ist es praktisch, das Dienstprogramm zu verwenden.

Die Arbeit mit dem Dienstprogramm besteht aus zwei einfachen Schritten:

  • Installation
  • Ziehen Sie die ausführbare Datei (* .exe, * .bat, * .cmd) per Drag & Drop auf die Verknüpfung des Dienstprogramms:


Autofokus auf ein laufendes Programm

Die Besonderheit beim Starten von Anwendungen aus dem Scheduler besteht darin, dass der Fokus nicht auf das Fenster übertragen wird und Sie beispielsweise, um einen Befehl in die Befehlszeile einzugeben, zusätzlich auf das Fenster klicken müssen. Dieses Verhalten kann bei der Automatisierung geplanter Routinevorgänge helfen, aber für Methode Nr. 4 ist es nicht immer bequem.

Es gibt mehrere Methoden zur "Abhilfe". Sie funktionieren ein wenig anders, also wählen Sie diejenige aus, die für Sie am besten geeignet ist. Der erste ist bequemer zum Ausführen von Programmen und der zweite zum Ausführen von Skripten.

Beim Erstellen einer Aufgabe hinzufügen:

Verwenden des Startbefehls

Programm oder Skript:

Argumente:

/c start /d "Programmpfad" Dateiname.exe

/c start /d "C:\Windows\System32\" cmd.exe

Verwenden des NirCmd-Dienstprogramms

Programm oder Skript:

Path_to_nircmd \ nircmd.exe

Argumente:

Exec show "Programmpfad \ Dateiname.exe"

Exec show "C:\Windows\System32\cmd.exe"

Dialog "Ausführen" als Administrator ausführen

Analog zum Starten der Befehlszeile können Sie den Start des Dialogfelds " Ausführen", und die eingegebenen Befehle werden auch im Namen des Administrators ausgeführt. Der Vorteil dieses Ansatzes besteht darin, dass die Liste der zuvor verwendeten Befehle gespeichert wird und Sie den gewünschten aus der Liste auswählen können.


Beim Erstellen einer Aufgabe im Planer, in der " Aktion erstellen"angeben:

auf dem Feld " Programm oder Skript":

Rundll32

auf dem Feld " Argumente hinzufügen":

Shell32.dll, # 61

Laden Sie das Dienstprogramm herunter, entpacken Sie es. Wir starten die Kommandozeile, geben den erforderlichen Befehl ein, die Syntax ist ganz einfach:

<путь к утилите> <путь к нужному приложению>


Eine UAC-Eingabeaufforderung wird angezeigt und die Anwendung wird als Administrator ausgeführt.

Notiz: V Kontextmenü Windows 7 hat eine sehr praktische Funktion zum Kopieren des Dateipfads: gedrückt halten Schicht, klicken Sie mit der rechten Maustaste auf die Datei, wählen Sie " Als Pfad kopieren".


Programme nach Benutzer als Administrator ausführen, ohne das Administratorkennwort einzugeben

Wichtig! Diese Methode ist unsicher, da sie es einem eingeschränkten Benutzer ermöglicht, Code mit vollen Rechten auszuführen. Ein gerissener Benutzer oder Malware kann dies ausnutzen und das System kompromittieren.

Betrachten Sie eine andere interessante Aufgabe: Ihr Konto Windows-Eintrag gehört zur Gruppe der Administratoren, es gibt einen oder mehrere Konten in die Benutzergruppe aufgenommen. Der Benutzer muss ein Programm ausführen, das eine Erhöhung erfordert. Normalerweise sieht es so aus: Der Benutzer klickt mit der rechten Maustaste auf die Datei und wählt "Als Administrator ausführen", wodurch das Administratorkennwort abgefragt wird:


Natürlich ist es keine gute Idee, Benutzern ein Administratorkennwort zu geben. Um dies zu umgehen, verwenden wir das Dienstprogramm AdmiLink von Alexey Kuryakin. Mit seiner Hilfe kann der Administrator eine Verknüpfung für den Benutzer erstellen, um das erforderliche Programm zu starten, während die Eingabe des Administratorkennworts nur einmal erforderlich ist - beim Erstellen einer Verknüpfung. Beim Programmstart durch den Benutzer wird das Passwort verschlüsselt übertragen.



Diese Methode funktioniert, wenn das Programm nur als Administrator ausgeführt werden kann und der Entwickler nicht vergessen hat, diese Bedingung im Manifest anzugeben. Es gibt jedoch noch eine große Anzahl alter Programme oder Programme, die sowohl im normalen Modus als auch als Administrator gestartet werden können (in diesem Fall stehen andere Funktionen zur Verfügung). Wenn Sie versuchen, ein solches Programm mit AdmiLink auszuführen, startet es im normalen Modus (ohne Administratorrechte). Und wenn Sie versuchen, das Kontrollkästchen "Methodennummer 3" zu aktivieren. Der ursprüngliche Stil des Autors wird gespeichert.

Gastroguru 2017