{"id":20171158,"url":"https://github.com/andreastedile/exploring-system-calls","last_synced_at":"2026-05-13T02:33:29.133Z","repository":{"id":106307618,"uuid":"157932848","full_name":"andreastedile/exploring-system-calls","owner":"andreastedile","description":"Una breve ricerca sulle system call basata sull'analisi dei dump dei file oggetto prodotti dalla compilazione di programmi C","archived":false,"fork":false,"pushed_at":"2020-10-24T19:13:46.000Z","size":8,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-03T04:26:15.182Z","etag":null,"topics":["c","linux","system-calls"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andreastedile.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-11-16T23:33:43.000Z","updated_at":"2022-06-02T18:52:19.000Z","dependencies_parsed_at":null,"dependency_job_id":"b9c1f9dc-004f-42ad-878e-52bc73daad9d","html_url":"https://github.com/andreastedile/exploring-system-calls","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/andreastedile/exploring-system-calls","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreastedile%2Fexploring-system-calls","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreastedile%2Fexploring-system-calls/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreastedile%2Fexploring-system-calls/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreastedile%2Fexploring-system-calls/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andreastedile","download_url":"https://codeload.github.com/andreastedile/exploring-system-calls/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreastedile%2Fexploring-system-calls/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32965328,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-12T23:30:32.555Z","status":"online","status_checked_at":"2026-05-13T02:00:07.132Z","response_time":115,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","linux","system-calls"],"created_at":"2024-11-14T01:23:36.504Z","updated_at":"2026-05-13T02:33:29.119Z","avatar_url":"https://github.com/andreastedile.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Esplorando le system call\r\n\r\nIn questo documento vediamo come si effettua una semplice system call in un computer con architettura Intel 64-bit e sistema operativo Linux-Ubuntu 18.04.1. Questa breve ricerca si fonda sull'analisi del file eseguibile prodotto dalla compilazione. Dapprima analizziamo il contenuto che si ottiene disassemblando un file eseguibile, e successivamente ci concentriamo su un programma Assembly.\r\n\r\nFonti interessanti:\r\n\r\nhttps://youtu.be/mB79rNrpOhg  \r\nhttps://youtu.be/VQAKkuLL31g  \r\nhttps://youtu.be/BWRR3Hecjao\r\n\r\n## Concetti preliminari\r\n\r\n### System call\r\n\r\nUn calcolatore consiste di numerosi dispositivi hardware che lavorano in armonia sotto la gestione del kernel del sistema operativo. Il kernel implementa un'interfaccia fra il livello dell'hardware e il livello del software, che comporta una serie di benefici:\r\n\r\n- Libera i programmatori dallo studio dei dettagli della programmazione a basso livello dei dispositivi.\r\n- Il kernel può controllare l'accuratezza delle richieste fatte al livello dell'interfaccia prima di soddisfarle.\r\n- I programmi diventano più portabili, in quanto possono eseguire correttamente su ogni kernel che espone lo stesso insieme di interfacce.\r\n\r\nIl kernel realizza questa interfaccia esponendo ai programmi delle **system call** con cui può essere richiamato.\r\n\r\nIn altre parole, una system call è un entry point controllato nel kernel del sistema operativo. I programmi fanno uso delle system call per richiedere i servizi del kernel, che quest'ultimo svolge orchestrando i dispositivi hardware.\r\n\r\nIn Linux, la libreria **glibc** dà modo di effettuare le system call.\r\n\r\n### C standard library\r\n\r\nQuesta libreria, cui ci si riferisce spesso con l'abbreviazione **libc**, contiene le funzioni standard che possono essere usate dai programmi C. La sua implementazione più usata su Linux è la GNU C Library, o **[glibc](https://www.gnu.org/software/libc/)**. La glibc arriva in due versioni, statica o dinamica, a seconda del tipo di compilazione che intendiamo conseguire.\r\n\r\nLa glibc contiene inoltre varie librerie di fondamentale importanza. In particolare, essa fornisce la API dello standard POSIX, che vediamo qui di seguito.\r\n\r\n### POSIX\r\n\r\nLo standard POSIX è nato per mantenere compatibilità fra sistemi operativi ed incrementare la portabilità dei programmi a livello di codice sorgente. Esso specifica una API uniforme che i programmatori possano usare sui sistemi operativi conformi allo standard. La API di POSIX comprende le funzioni fondamentali che un sistema operativo mette tipicamente a disposizione: `open`, `read`, `close`, `write`, `fork`...\r\n\r\nLo standard non prescrive una particolare implementazione della API, ma si occupa esclusivamente della specificarne le funzioni e il servizio che devono realizzare.\r\n\r\nValgono le seguenti considerazioni:\r\n\r\n- POSIX si riferisce ad una API e non ad un'implementazione.\r\n- In virtù di questo fatto, i servizi descritta dalla specifica POSIX si possono implementare sia in User mode che in Kernel mode (nel secondo caso, viene fatto uso di system call).\r\n- La distinzione fra API e system call è irrilevante per il programmatore, che fa unicamente fede al comportamento atteso della funzione (nome, tipo dei parametri, significato del valore di ritorno), mentre è rilevante per il designer di un kernel, che deve poter riconoscere se la funzione lavora in Kernel mode (è una system call) o in User mode.\r\n- Un sistema può fregiarsi della certificazione POSIX se espone al programmatore una API che è conforme allo standard POSIX.\r\n\r\n### Chiamare il kernel Linux\r\n\r\nLa API dello standard POSIX è implementata in Linux dalla glibc, e il suo accesso è consentito dall'header `unistd.h`.\r\n\r\nAlla luce di questo fatto, una chiamata ad una funzione della API è in realtà una chiamata ad una funzione wrapper, che si occupa di inserire i valori corretti nei registri per poi effettuare una trap che restituisce il controllo al kernel.\r\n\r\nLe system call *vere e proprie*, infatti, sono implementate da routine scritte nel linguaggio Assembly per una specifica architettura hardware; mentre le system call fornite dalla C standard library sono in realtà dei comodi wrapper che nascondono l'implementazione della system call vera e propria. Questo ulteriore livello di indirizzamento incrementa la modularità e portabilità.\r\n\r\n![](https://qph.fs.quoracdn.net/main-qimg-28627e0d73ba1753783422fd0cf70751)\r\n\r\nÈ tuttavia uso comune e corretto riferirsi a queste funzioni wrapper come *system call*, in quanto il loro effetto ultimo è di fatto quello di invocare una system call.\r\n\r\nIn Linux, volendo, si può invocare una system call per cui glibc non fornisce un wrapper dedicato attraverso la funzione [`syscall`](http://man7.org/linux/man-pages/man2/syscall.2.html), che vedremo successivamente.\r\n\r\nSinteticamente, le funzioni wrapper della glibc seguono questi [tre passaggi](http://man7.org/linux/man-pages/man2/intro.2.html#DESCRIPTION) chiave:\r\n\r\n- Copiano il numero univoco della system call e i parametri nei registri laddove il kernel li aspetta.\r\n- Effettuano una trap in Kernel mode: ora il kernel svolge il vero lavoro della system call.\r\n- Quando il kernel fa tornare la CPU in User mode, settano `errno` se la system call ha ritornato un numero di errore.\r\n\r\n### Architetture e kernel\r\n\r\nOgni architettura ha i propri requisiti per invocare il kernel e passargli parametri.\r\n\r\nVediamo per qualche architettura l' istruzione che consegue la transizione in Kernel mode:\r\n\r\n| arch/ABI |   istr    | #syscall | retval |\r\n| :------: | :-------: | :------: | :----: |\r\n|   i386   | int $0x80 |   eax    |  eax   |\r\n|  x86-64  |  syscall  |   rax    |  rax   |\r\n|  arm64   |  svc #0   |    x8    |   x0   |\r\n\r\nVediamo anche i registri usati per passare gli argomenti delle system call:\r\n\r\n| arch/ABI | arg1 | arg2 | arg3 | arg4 | arg5 | arg6 |\r\n| :------: | :--: | :--: | :--: | :--: | :--: | :--: |\r\n|   i386   | ebx  | ecx  | edx  | esi  | edi  | ebp  |\r\n|  x86-64  | rdi  | rsi  | rdx  | r10  |  r8  |  r9  |\r\n|  arm64   |  x0  |  x1  |  x2  |  x3  |  x4  |  x5  |\r\n\r\n### Le system call di Linux\r\n\r\nAbbiamo visto che l'accesso alla API del kernel Linux, che è conforme allo standard POSIX, è consentito da `unistd.h`, un header che contiene oltretutto le definizioni di [alcune system call](https://stackoverflow.com/questions/30155858/are-unix-linux-system-calls-part-of-posix-library-functions) non previste da POSIX.\r\n\r\n## Un primo programma\r\n\r\nIniziamo, scrivendo nel file *hello.c* il seguente programma C:\r\n\r\n```c\r\n#include \u003cstdio.h\u003e\r\nint main()\r\n{\r\n\tprintf(\"Hello, World!\\n\");\r\n\treturn 0;\r\n}\r\n```\r\n\r\nL'header `stdio.h` contiene la definizione della funzione `printf`, implementata dalla C standard library.\r\n\r\nCompiliamo *hello.c* in *hello.out* con `gcc -o hello.out hello.c`.\r\n\r\nEseguendo *hello.out* otteniamo l'output:\r\n\r\n```\r\nHello, World!\r\n```\r\n\r\nCon `ls -l` verifichiamo che *hello.c* ha una dimensione di 8.10 kilobyte ed *hello.out* di 8.3 kilobyte.\r\n\r\nCon `file hello.out` verifichiamo che le librerie per *hello.out* sono state linkate dinamicamente:\r\n\r\n\u003e andreastedile@ubuntu:~/Desktop/Syscalls$ file hello.out \r\n\u003e hello.out: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=88cd59f387301bdc8abe58360ea55b641135b5c7, not stripped\r\n\r\nElenchiamo queste librerie con `ldd hello.out`:\r\n\r\n\u003e andreastedile@ubuntu:~/Desktop/Syscalls$ ldd hello.out \r\n\u003e ​\tlinux-vdso.so.1 =\u003e  (0x00007ffef037f000)\r\n\u003e ​\tlibc.so.6 =\u003e /lib/x86_64-linux-gnu/libc.so.6 (0x00007f617ecb7000)\r\n\u003e ​\t/lib64/ld-linux-x86-64.so.2 (0x000055d764da7000)\r\n\r\n[`linux-vdso.so.1`](http://man7.org/linux/man-pages/man7/vdso.7.html) è una shared library che aumenta la performance di alcune system call.\r\n\r\n[`libc.so.6`](http://man7.org/linux/man-pages/man7/libc.7.html) è la C standard library di Linux che è stata linkata dinamicamente.\r\n\r\n## Prima esplorazione\r\n\r\nCon `objdump -d hello.out` disassembliamo il file binario `hello.out`. Analizziamo solo alcune parti dell'output, che è molto grande:\r\n\r\n```assembly\r\n000000000000063a \u003cmain\u003e:\r\n 63a:\t55                   \tpush   %rbp\r\n 63b:\t48 89 e5             \tmov    %rsp,%rbp\r\n 63e:\t48 8d 3d 9f 00 00 00 \tlea    0x9f(%rip),%rdi\r\n 645:\te8 c6 fe ff ff       \tcallq  510 \u003cputs@plt\u003e\r\n 64a:\tb8 00 00 00 00       \tmov    $0x0,%eax\r\n 64f:\t5d                   \tpop    %rbp\r\n 650:\tc3                   \tretq   \r\n 651:\t66 2e 0f 1f 84 00 00 \tnopw   %cs:0x0(%rax,%rax,1)\r\n 658:\t00 00 00 \r\n 65b:\t0f 1f 44 00 00       \tnopl   0x0(%rax,%rax,1)\r\n```\r\n\r\n`push %rbp` e `pop %rbp` sono usate rispettivamente nel prologo e nell'epilogo delle subroutine, per salvare sullo stack il contenuto di un registro o prelevare dallo stack il contenuto della memoria.\r\n\r\n`%rbp` e `%rsp` sono due registri special purpose, rispettivamente usati come *base pointer* (puntatore alla base del record di attivazione della subroutine corrente) e *stack pointer* (puntatore alla cima del record di attivazione della subroutine corrente). In realtà, in questo programma, questi due registri non sono strettamente necessari, in quanto nella funzione `main` non vi sono variabili locali cui bisogni riferirsi.\r\n\r\n`lea 0x9f(%rip),%rdi` carica in `%rdi` l'indirizzo di memoria dato dalla somma di `%rip` (un registro special purpose puntatore all'istruzione corrente) e 0x9f, cioè 6e4 (645 - 9f). All'indirizzo 6e4 si trova la stringa `Hello, World!\\n`. Più precisamente, la stringa è contenuta nella sezione `.rodata`, che possiamo analizzare con `objdump -s hello.out -j .rodata`:\r\n\r\n```assembly\r\nhello.out:     file format elf64-x86-64\r\n\r\nContents of section .rodata:\r\n 06e0 01000200 48656c6c 6f2c2057 6f726c64 ....Hello, World\r\n 06f0 2100                              \t!.                   \r\n```\r\n\r\n`callq 510` è un'invocazione della subroutine all'indirizzo di memoria 510:\r\n\r\n```assembly\r\n0000000000000510 \u003cputs@plt\u003e:\r\n 510:\tff 25 ba 0a 20 00    \tjmpq   *0x200aba(%rip)        # 200fd0 \u003cputs@GLIBC_2.2.5\u003e\r\n 516:\t68 00 00 00 00       \tpushq  $0x0\r\n 51b:\te9 e0 ff ff ff       \tjmpq   500 \u003c.plt\u003e\r\n```\r\n\r\nIl compilatore, accorgendosi che `Hello, World!\\n` è una *string literal*, ha effettuato un'ottimizzazione traducendo `printf` in `puts`.\r\n\r\nInfine, `mov $0x0,%eax` corrisponde a `return 0;` del codice in C.\r\n\r\nSiamo arrivati fin qua, ma c'è un \"problema\": l'istruzione `jmpq` (all'indirizzo di memoria 510), che salta alla subroutine all'indirizzo 200fd0, non è che una reference alla C standard library (in altre parole, è la funzione wrapper di cui parlavamo, che si occupa di gestire per noi la system call per `puts`).\r\n\r\nPertanto, rintracciare la parte di codice che rappresenta la system call è abbastanza problematico: ci serve un \"escamotage\".\r\n\r\n## Un tentativo\r\n\r\nProviamo a cambiare il programma C invocando la funzione `write`:\r\n\r\n```c\r\n#include \u003cunistd.h\u003e\r\nint main()\r\n{\r\n\twrite(1, \"Hello, World!\\n\", 14);\t//1: file descriptor, 14: byte\r\n\treturn 0;\r\n}\r\n```\r\n\r\nL'header `unistd.h` contiene la definizione della funzione `write`.\r\n\r\nQuesta funzione fa parte della API che i sistemi operativi conformi allo standard POSIX devono mandatoriamente implementare. Nonostante non sia funzione richiesta dallo standard del linguaggio C, è la C standard library a fornirne un'implementazione.\r\n\r\nÈ possibile scrivere qualcosa di ancor più basso livello? Sì: come abbiamo accennato prima, `unistd.h` mette a disposizione la funzione `syscall`, che permette di invocare una qualsiasi system call e si rivela particolarmente utile quando la glibc non fornisce un wrapper per quest'ultima.\r\n\r\nL'header `sys/syscall.h` contiene le costanti simboliche delle system calls.\r\n\r\nModifichiamo nuovamente il programma C nella maniera seguente:\r\n\r\n```c\r\n#include \u003cunistd.h\u003e\r\n#include \u003csys/syscall.h\u003e\r\nint main()\r\n{\r\n\tsyscall(SYS_write, 1, \"Hello, World!\\n\", 14);\r\n    \treturn 0;\r\n}\r\n```\r\n\r\nIl programma si può ancora compilare ed eseguire correttamente.\r\n\r\nDisassembliamo nuovamente l'eseguibile con `objdump -d hello.out`:\r\n\r\n```assembly\r\n000000000000064a \u003cmain\u003e:\r\n 64a:\t55                   \tpush   %rbp\r\n 64b:\t48 89 e5             \tmov    %rsp,%rbp\r\n 64e:\tb9 0e 00 00 00       \tmov    $0xe,%ecx\r\n 653:\t48 8d 15 aa 00 00 00 \tlea    0xaa(%rip),%rdx\r\n 65a:\tbe 01 00 00 00       \tmov    $0x1,%esi\r\n 65f:\tbf 01 00 00 00       \tmov    $0x1,%edi\r\n 664:\tb8 00 00 00 00       \tmov    $0x0,%eax\r\n 669:\te8 b2 fe ff ff       \tcallq  520 \u003csyscall@plt\u003e\r\n 66e:\tb8 00 00 00 00       \tmov    $0x0,%eax\r\n 673:\t5d                   \tpop    %rbp\r\n 674:\tc3                   \tretq   \r\n 675:\t66 2e 0f 1f 84 00 00 \tnopw   %cs:0x0(%rax,%rax,1)\r\n 67c:\t00 00 00 \r\n 67f:\t90                   \tnop\r\n```\r\n\r\nNotiamo quattro istruzioni:\r\n\r\n- `mov $0xe,%ecx` mette il valore 14 nel registro `%ecx`,\r\n- `lea 0xaa(%rip),%rdx` mette l'indirizzo della stringa `Hello, World!\\n` in `%rdx`,\r\n- `mov $0x1,%esi` e `mov $0x1,%edi` mettono il valore 1 nei registri `%esi` e `%edi`. Questi argomenti rappresentano il numero della system call che vogliamo effettuare e il file descriptor per lo standard output.\r\n\r\nQueste istruzioni realizzano il passaggio degli argomenti alla subroutine invocata successivamente con l'istruzione `callq 520`.\r\n\r\nAll'indirizzo di memoria 520 troviamo nuovamente una reference alla C standard library.\r\n\r\n```assembly\r\n 0000000000000520 \u003csyscall@plt\u003e:\r\n 520:\tff 25 aa 0a 20 00    \tjmpq   *0x200aaa(%rip)        # 200fd0 \u003csyscall@GLIBC_2.2.5\u003e\r\n 526:\t68 00 00 00 00       \tpushq  $0x0\r\n 52b:\te9 e0 ff ff ff       \tjmpq   510 \u003c.plt\u003e\r\n```\r\n\r\nNon abbiamo ancora avuto modo di vedere una vera e propria invocazione della system call...\r\n\r\n## Static linking\r\n\r\nPer andare avanti nella nostra missione esplorativa, linkiamo staticamente le librerie. Questo si consegue con l'opzione **static** per il linker: `gcc -static -o hello.out hello.c`. Sostanzialmente, il linker estrae il codice necessario dalla versione statica della C standard library, `libc.a`, che verrà iniettato nel file eseguibile. In questo modo, nel file eseguibile saranno incluse le istruzioni che realizzano la system call.\r\n\r\nDal momento che le librerie sono state linkate staticamente, la dimensione di *hello.out* cresce a 895 kilobyte, ed è ben maggiore rispetto agli 8.3 kilobyte precedenti.\r\n\r\n`ldd hello.out` indica, giustamente,\r\n\r\n\u003e not a dynamic executable\r\n\r\nAnalizziamo alcune parti di `hello.out`.\r\n\r\nNella sezione `main` vi sono le usuali istruzioni che realizzano lo scambio dei parametri per l'imminente invocazione di procedura, e l'unico cambiamento interessante è dato dall'istruzione:\r\n\r\n```assembly\r\n  400b6c:\te8 ef 93 04 00       \tcallq  449f60 \u003csyscall\u003e\r\n```\r\n\r\nAll'indirizzo di memoria 449f60 abbiamo:\r\n\r\n```assembly\r\n0000000000449f60 \u003csyscall\u003e:\r\n  449f60:\t48 89 f8             \tmov    %rdi,%rax\r\n  449f63:\t48 89 f7             \tmov    %rsi,%rdi\r\n  449f66:\t48 89 d6             \tmov    %rdx,%rsi\r\n  449f69:\t48 89 ca             \tmov    %rcx,%rdx\r\n  449f6c:\t4d 89 c2             \tmov    %r8,%r10\r\n  449f6f:\t4d 89 c8             \tmov    %r9,%r8\r\n  449f72:\t4c 8b 4c 24 08       \tmov    0x8(%rsp),%r9\r\n  449f77:\t0f 05                \tsyscall \r\n  449f79:\t48 3d 01 f0 ff ff    \tcmp    $0xfffffffffffff001,%rax\r\n  449f7f:\t73 01                \tjae    449f82 \u003csyscall+0x22\u003e\r\n  449f81:\tc3                   \tretq   \r\n  449f82:\t48 c7 c1 c0 ff ff ff \tmov    $0xffffffffffffffc0,%rcx\r\n  449f89:\tf7 d8                \tneg    %eax\r\n  449f8b:\t64 89 01             \tmov    %eax,%fs:(%rcx)\r\n  449f8e:\t48 83 c8 ff          \tor     $0xffffffffffffffff,%rax\r\n  449f92:\tc3                   \tretq   \r\n  449f93:\t66 2e 0f 1f 84 00 00 \tnopw   %cs:0x0(%rax,%rax,1)\r\n  449f9a:\t00 00 00 \r\n  449f9d:\t0f 1f 00             \tnopl   (%rax)\r\n```\r\n\r\nSi tratta dell'implementazione vera e propria della system call `write`, che, come vediamo, effettua una trap nel kernel mediante l'istruzione `syscall`.\r\n\r\n## Osservazioni finali\r\n\r\nOra che abbiamo potuto apprezzare la natura di basso livello di una system call, concludiamo con un'ultima osservazione.\r\n\r\nCompiliamo il file *hello.c* nel file assembly *hello.S* con il comando `gcc -S hello.c -o hello.S`. \r\n\r\nEsaminiamo *hello.s*:\r\n\r\n```assembly\r\n\t.file\t\"hello.c\"\r\n\t.text\r\n\t.section\t.rodata\r\n.LC0:\r\n\t.string\t\"Hello, World!\\n\"\r\n\t.text\r\n\t.globl\tmain\r\n\t.type\tmain, @function\r\nmain:\r\n.LFB0:\r\n\t.cfi_startproc\r\n\tpushq\t%rbp\r\n\t.cfi_def_cfa_offset 16\r\n\t.cfi_offset 6, -16\r\n\tmovq\t%rsp, %rbp\r\n\t.cfi_def_cfa_register 6\r\n\tmovl\t$14, %ecx\r\n\tleaq\t.LC0(%rip), %rdx\r\n\tmovl\t$1, %esi\r\n\tmovl\t$1, %edi\r\n\tmovl\t$0, %eax\r\n\tcall\tsyscall@PLT\r\n\tmovl\t$0, %eax\r\n\tpopq\t%rbp\r\n\t.cfi_def_cfa 7, 8\r\n\tret\r\n\t.cfi_endproc\r\n.LFE0:\r\n\t.size\tmain, .-main\r\n\t.ident\t\"GCC: (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0\"\r\n\t.section\t.note.GNU-stack,\"\",@progbits\r\n```\r\n\r\nAnche qui, in linea con le nostre aspettative, notiamo le istruzioni per il passaggio dei parametri, con i valori corretti.\r\n\r\n### Vi sono margini di miglioramento?\r\n\r\nSì, in quanto gcc ha più volte inserito molti elementi non necessari alla stampa della stringa `Hello, World!\\n.` Un giorno mostreremo come ridurre al minimo il codice Assembly :-)\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandreastedile%2Fexploring-system-calls","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandreastedile%2Fexploring-system-calls","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandreastedile%2Fexploring-system-calls/lists"}