[LINUX] Ich habe Hello World mit 64-Bit-OS + C-Sprache ohne Verwendung einer Bibliothek ausprobiert

Dieser Artikel wurde als Artikel zum 8. Tag von [OthloTech Adventskalender 2017] geschrieben (https://qiita.com/advent-calendar/2017/othlotech).

Ich bin seit gestern an zwei aufeinander folgenden Tagen dafür verantwortlich. Gestern ging es um Mobile, aber heute möchte ich den Kernel in C-Sprache ändern und ansprechen. Insbesondere wird Hello World nur mit den im Betriebssystem definierten Systemaufrufen ausgeführt.

__ Zielgruppe __

** Artikelinhalt **

** Betriebsumgebung **

Die erste Hallo Welt

Schreiben wir Hello World, die mit C am einfachsten zu sein scheint. Es ist etwas, das viele Leute geschrieben haben, wie zum Beispiel das Lernen in der Schule.

Hello.c


#include<stdio.h>

int main(){
  printf("Hello World!\n");
  return 0;
}

Ich habe es im Druckformat geschrieben. Sie können es einfach anzeigen, indem Sie eine Zeichenfolge angeben. Diese Funktion namens printf funktioniert jedoch nur, wenn stdio.h enthalten ist. Es ist eine sogenannte magische. Die Bedienung im Inneren wird allein dadurch nicht gut verstanden.

Lassen Sie uns kompilieren und sehen, wie die ausführbare Datei aussieht. Da es mit gdb debuggt, wird die Option -g hinzugefügt, und der dynamische Link ist faul, daher wird -static hinzugefügt.

$ gcc Hello.c -static -g
$ gdb -q a.out
(gdb) break main
(gdb) layout asm
(gdb) run
(gdb) si
(gdb) si
     ...

Ich habe versucht, so zu treten, wie es ist, aber es endet nicht leicht. ~~ Ich bin bis zum Ende nicht motiviert ~~ Ich bin mir nicht sicher, wie es funktioniert, also drücke ich strace, einen Befehl, der Systemaufrufe auflistet.

$ strace ./a.out
                                                 ~/hello
execve("./a.out", ["./a.out"], 0x7ffdd8a3ad60 /* 43 vars */) = 0
brk(NULL)                               = 0x1182000
brk(0x11831c0)                          = 0x11831c0
arch_prctl(ARCH_SET_FS, 0x1182880)      = 0
uname({sysname="Linux", nodename="Juju-62q", ...}) = 0
readlink("/proc/self/exe", "/home/(username)/hello/a.out", 4096) = 23
brk(0x11a41c0)                          = 0x11a41c0
brk(0x11a5000)                          = 0x11a5000
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
write(1, "Hello World\n", 12Hello World
)           = 12
exit_group(0)                           = ?
+++ exited with 0 +++

Es scheint, dass das Gedächtnis irgendwie gesichert ist und verschiedene Dinge getan werden. Ich bin jedoch der Meinung, dass beim Schreiben eine Zeichenfolge angezeigt werden kann. Als nächstes werde ich dies verwenden, um eine Zeichenfolge auszugeben.

Versuchen Sie es mit der Schreibfunktion in C-Sprache

Als ich nach der Schreibfunktion suchte, wurde sie wie folgt definiert. (/usr/include/unistd.h) extern ssize_t write (int __fd, const void *__buf, size_t __n) __wur; fd ist ein Dateideskriptor. Dieses Mal ist es 1, da es an die Standardausgabe ausgegeben wird. buf ist der Ausgabeinhalt und n ist die Anzahl der Zeichen. Es scheint unpraktisch zu sein als printf, aber es scheint, dass die Unannehmlichkeit nicht bequem ist, so dass es mehr Dinge gibt, die nicht verwendet werden () Lassen Sie uns dies einschließen.

Write.c


#include<unistd.h>

int main(){
  const void *string = "Hello Write!\n";
  write(1, string, 13);
  return 0;
}

Ich habe versucht, eine Zeichenfolge in der Standardausgabe anzuzeigen. Lassen Sie es auf die gleiche Weise funktionieren.

$ gcc Write.c -static -g
$ gdb -q a.out
(gdb) break main
(gdb) layout asm
(gdb) run
(gdb) si
(gdb) si
     ...

Dieses Mal kam ich relativ schnell zur Anzeige der Zeichen. Anscheinend wird es beim Aufruf von syscall angezeigt. Aber ich mag #include <unistd.h> nicht. Wenn eine Zeichenkette von syscall angezeigt wird, sollten Sie sie festlegen und syscall aufrufen. Daher habe ich untersucht, wie syscall verwendet wird. Anscheinend von den von der 64-Bit-CPU verwendeten Registern

rax = 1 (gibt an, dass es sich um einen Schreibsystemaufruf handelt) rdi = 1 (Dateideskriptor, dh 1 für Standardausgabe) rsi = (erste Adresse der Zeichenfolge) (Anzeigezeichenfolge angeben) rdx = (Länge der Zeichenfolge) (Anzahl der Zeichen)

Es scheint, dass die Zeichenfolge angezeigt wird, wenn syscall als aufgerufen wird. Als nächstes rufen wir syscall direkt vom Assembler aus auf. Dann können Sie sich von der verhassten Unistd.h verabschieden.

Ich beziehe mich auf Folgendes http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/

Klicken Sie hier für CPU-Register https://software.intel.com/en-us/articles/introduction-to-x64-assembly

Rufen Sie syscall mit dem Assembler auf, um zu sehen

Beim Aufrufen in C-Sprache scheint es, dass die obigen Spezifikationen nur erfüllt werden können, wenn mindestens die Zeichenfolge und die Zeichenlänge angegeben sind. Daher möchte ich das Argument angeben. Wenn Sie das Argument mit einem 64-Bit-Assembler verwenden, scheint es wie folgt zu funktionieren.

rdi erstes argument rsi zweites Argument rdi 3. Argument rcx 4. Argument r8 5. Argument r9 6. Argument

Referenz http://p.booklog.jp/book/34047/page/613687

Da es diesmal zwei Argumente gibt, werden wir rdi und rsi verwenden. Speichern Sie dann die erste Adresse der Zeichenfolge in rsi, die Anzahl der Zeichen in rdx und 1 in rax und rdi. Basierend auf dem oben Gesagten habe ich einen Assembler für Nasm geschrieben. Der Funktionsname ist Hallo.

syscall.asm


bits 64

global hello

hello:
  mov rdx, rsi
  mov rsi, rdi
  mov rax, 1
  mov rdi, 1
  syscall
  ret

Ich habe ein C-Sprachprogramm mit den vom Assembler erstellten Funktionen geschrieben.

main.c


void hello(char *string, int len);

int main (){
  char *string = "Hello Asm!\n";
  hello(string, 11);
  return 0;
}

Endlich ist das Include weg !!! In der Sprache C wird der Hallo-Prototyp deklariert und die Funktion ausgeführt. Lassen Sie es uns kompilieren. Dieses Mal wird eine Objektdatei generiert und verknüpft, um mehrere Dateien zu verbinden.

$ nasm -f elf64 -o syscall.o syscall.asm
$ gcc -c main.c
$ gcc main.o syscall.o
$ ./a.out
Hello Asm!

Ich konnte die Zeichenfolge, die ich ausgeben möchte, sicher ausgeben! In nasm wird -f elf64 angegeben, um die Objektdatei für 64bit auszugeben. Hello World (vorläufig) wurde nur durch Systemaufrufe vom Betriebssystem erstellt, ohne die Bibliothek sicher zu verwenden! Natürlich ist es ein rudimentärer Anfang, aber ich habe das Gefühl, ein wenig über die Verwendung des Betriebssystems gelernt zu haben.

Nachtrag: Bezüglich der Startroutine

Eine Startroutine, die beim Aufrufen einer Funktion Hauptargumente verarbeitet und am Ende zurückgibt, wird aus der Bibliothek aufgerufen. Ich habe einen Kommentar erhalten.

Vorerst werde ich das Programm veröffentlichen, das nicht die Startroutine verwendet, die ich erhalten habe. Ich werde es erneut aktualisieren, wenn ich es in mich selbst einfügen kann.

$ cat -n main.c
     1  void hello(const char*, int);
     2  void exit(int) __attribute__((noreturn));
     3
     4  int main(void){
     5    const char* string = "Hello Asm!\n";
     6    hello(string, __builtin_strlen(string));
     7    exit(0);
     8  }
$ cat -n syscall.asm
     1  bits 64
     2
     3  global hello
     4
     5  hello:
     6    mov rdx, rsi
     7    mov esi, edi
     8    mov eax, 1
     9    mov edi, 1
    10    syscall
    11    ret
    12
    13  global exit
    14
    15  exit:
    16    mov esi, edi
    17    mov eax, 60
    18    syscall
$ cat -n makefile
     1  target:
     2          nasm -f elf64 -o syscall.o syscall.asm
     3          gcc -O2 -Wall -Wextra main.c syscall.o -nostdlib -static -Wl,-Map=main.map -Wl,-emain
$ make
nasm -f elf64 -o syscall.o syscall.asm
gcc -O2 -Wall -Wextra main.c syscall.o -nostdlib -static -Wl,-Map=main.map -Wl,-emain
$ ls -l a.out
-rwxrwxrwx 1 user user 1504 Dec  9 00:00 a.out
$ ./a.out
Hello Asm!
$

Zusammenfassung

Wie war das? ~~ Ich hoffe du verstehst wie hochklassig C Sprache ist. ~~ Ich würde mich sehr freuen, wenn Sie diesen Artikel aufrufen und den Spaß und die Tiefe von Systemaufrufen erkennen könnten. Es gibt nur wenige Leute in OthloTech, die Low Layer machen, also hoffe ich persönlich, dass es in Zukunft zunehmen wird lol Dann habt alle ein gutes Hack-Leben!

Recommended Posts

Ich habe Hello World mit 64-Bit-OS + C-Sprache ohne Verwendung einer Bibliothek ausprobiert
Ich habe versucht, die Python-Bibliothek von Ruby mit PyCall zu verwenden
Ich habe versucht, die funktionale Programmierbibliothek toolz zu verwenden
Ich habe versucht, mit der Bibliothek GiNZA zur Verarbeitung natürlicher Sprache eindeutige Ausdrücke zu extrahieren
Ich habe versucht, die Sprache mit CNN + Melspectogram zu identifizieren
Ich habe die Changefinder-Bibliothek ausprobiert!
Ich habe versucht, die Zeit und die Zeit der C-Sprache zu veranschaulichen
Ich habe versucht, die checkio-API zu verwenden
Python-Anfänger haben Hello World in 30 Sekunden mit der Mikroframework-Flasche ausprobiert
Ich habe versucht, Amazon SQS mit Django-Sellerie zu verwenden
Ich habe versucht, Selen mit Headless-Chrom zu verwenden
Ich habe versucht, die Lernfunktion im neuronalen Netzwerk sorgfältig zu verstehen, ohne die Bibliothek für maschinelles Lernen zu verwenden (zweite Hälfte).
Ich habe eine funktionale Sprache mit Python ausprobiert
Ich habe versucht, mit Pillow mit dem Bild zu spielen
Ich habe versucht, das Modell mit der Low-Code-Bibliothek für maschinelles Lernen "PyCaret" zu visualisieren.
Ich habe versucht, natürliche Sprache mit Transformatoren zu verarbeiten.
Ich habe versucht, die BigQuery-Speicher-API zu verwenden
Ich habe versucht, die Lernfunktion im neuronalen Netzwerk sorgfältig zu verstehen, ohne die Bibliothek für maschinelles Lernen zu verwenden (erste Hälfte).
[Python] Deep Learning: Ich habe versucht, Deep Learning (DBN, SDA) ohne Verwendung einer Bibliothek zu implementieren.
Ich habe versucht, die Python-Bibliothek "pykakasi" zu verwenden, die Kanji in Romaji konvertieren kann.
Ich habe die Zeit gemessen, als ich das C-sprachabhängige Modul mit alpine installiert habe
Ich habe versucht, das Bild mit Python + OpenCV zu "glätten"
Ich habe in der Bibliothek nach der Verwendung der Gracenote-API gesucht
vprof - Ich habe versucht, den Profiler für Python zu verwenden
Hallo Welt mit allen Funktionen der Go-Sprache
Ich habe versucht, das Bild mit Python + OpenCV zu "differenzieren"
Ich habe versucht, die Daten mit Zwietracht zu speichern
Ich habe versucht, PyCaret mit der schnellsten Geschwindigkeit zu verwenden
Ich habe versucht, die Google Cloud Vision-API zu verwenden
Begrüßen Sie die Welt mit Python mit IntelliJ
Ich habe versucht, Mecab mit Python2.7, Ruby2.3, PHP7 zu verwenden
Ich habe versucht, das Bild mit Python + OpenCV zu "binarisieren"
Ich habe versucht, Pythonect, eine Programmiersprache für den Datenfluss, zu verwenden.
Ich habe versucht, das Datetime-Modul von Python zu verwenden
Ich habe die Pepper NAOqi OS 2.5.5 SLAM-Funktion ausprobiert
Ich habe versucht, den Bildfilter von OpenCV zu verwenden
Ich habe DBM mit Pylearn 2 unter Verwendung künstlicher Daten ausprobiert
Ich habe versucht, die Datenbank (sqlite3) mit kivy zu verwenden
Ich habe versucht, mit tkinter mit dem Taschenrechner zu spielen
[MQTT] Ich habe versucht, mit einem Gerät über AWS IoT Core und Soracom Beam zu sprechen.
[Nichtkorrelationstest] Ich habe versucht, die Grenzlinie mit oder ohne Ablehnung zu löschen
Rufen Sie mit Go mit cgo Ihre eigene C-Sprachbibliothek auf
Ich habe versucht, Google Test und CMake in C zu verwenden
Ich habe versucht, BERT mit Sakura VPS (ohne GPU) auszuführen.
Ich habe versucht, eine CSV-Datei mit Python zu berühren
Ich habe versucht, Soma Cube mit Python zu lösen
FizzBuzz mit regulären Ausdrücken usw. ohne Verwendung des Operators '%'
[Linux] Ich habe versucht, die genetische Statistiksoftware PLINK zu verwenden
Ich habe versucht, EKG-Daten mit der K-Shape-Methode zu gruppieren
Ich habe versucht, die Sündenfunktion mit Chainer zu approximieren
Ich habe versucht, die API von Sakenowa Data Project zu verwenden
Ich habe versucht, das Problem mit Python Vol.1 zu lösen
Ich habe versucht, das Wissensdiagramm mit OpenKE zu ergänzen
Ich habe versucht, die API mit dem Python-Client von echonest zu erreichen
Ich habe versucht, das Bild mithilfe von maschinellem Lernen zu komprimieren
Ich habe versucht, die häufig verwendete Seaborn-Methode mit so wenig Argumenten wie möglich anzuwenden [für Anfänger]