Concrètement, en vulgarisant (mais pas trop =), ça pourrait ressembler à quelque chose de similaire.
Ton code source est celui ci. Il va devoir être compilé (ou interprété) afin d'être exécuté (ici, sur une arch x86_64).
Code:
une_fonction () {
une_chaine = "Hello world\n";
print une_chaine;
}
Comme tu l'as dit, il suffit de traduire ce code (une suite d'octets représentant des valeurs ascii) en suite d'octets représentant des instructions. Ton compilateur (ou interpréteur) connait la syntaxe de ton langage et va remplacer cela par les valeurs correspondantes aux instructions dans un fichier exécutables (ou le faire lors de l'exécution pour l'interpreteur).
Lors de son exécution, l'os va charger les instructions de ton programme en mémoire. Cela *pourrait* ressembler à quelque chose du genre si on examinait le contenu de celle ci.
Code:
push rbp ; function prologue
mov rbp, rsp
sub rsp, 0x10
mov QWORD_PTR[rbp - 0x10], 0x6f77206f6c6c6548 ; ow olleH
mov DWORD_PTR[rbp - 0x8], 0x0a646c72 ; \ndlr
mov rax, 0x1 ; write() system call
mov rdi, 0x1 ; descripteur de fichier 1 (stdout)
lea rsi, [rbp - 0x10] ; adresse de la chaine de caractère "Hello world\n" (chut)
mov rdx, 0xb ; longueur de la chaine de caractère
int 0x80 ; interuption
;passe le relais au kernel qui va alors s'occuper d'aller écrire la chaine de caractère à l'adresse corespondante à stdout (sans importance)
leave ; function epilogue (mov rsp, rbp // pop rpb)
ret
Il s'agit de la suite d'instructions du programme (en
asm). Chacune de ces lignes est en réalité une suite d'octets (l'asm est la pour simplifier la lecture) représentant une instruction.
Par exemple, les deux premières ressemblent en réalité à quelque chose de similaire (cette fois ci en hexadecimal):
Comprendre ce code a peu d'importance (il ne correspond de toute manière pas totalement à la réalité).
Mais on voit bien qu'il serait facile d'écrire un programme qui transformerait, par exemple, une_chaine = "Hello world\n" en cette série de trois instructions:
Code:
sub rsp, 0x10
mov QWORD_PTR[rbp - 0x10], 0x6f77206f6c6c6548 ; ow olleH
mov DWORD_PTR[rbp - 0x8], 0x0a646c72 ; \ndlr
J'espère que ça t'aidera à y voir plus clair et non pas l'inverse (et que je n'ai pas raconté trop de conneries). J'ai un gros doute après relecture..
Et puisque ça parlait initialement de livres. Sur le sujet, sans partir trop loin, pour "dégrossir" un peu le fonctionnement d'un système d'exploitation, je recommande "The Linux programming interface" de Michael Kerisk (il n'existe malheureusement pas en français :/).
Faire du C peut également énormément aider à comprendre si on s'intéresse un minima aux différentes phases de la compilation et de l'édition de liens (linker, dynamic loader).
Se renseigner sur le format des exécutables (que ça soit PE ou ELF) peut également être pas mal.