3.01 Programma C ad Assembly - follen99/ArchitetturaDeiCalcolatori GitHub Wiki

Da un programma C ad Assembly

Sappiamo tutti che per eseguire un programma scritto in C questo va prima compilato e poi eseguito. In realtà i passaggi sono molti più di questa semplice "traduzione", e sono ben spiegati quì.

Ad ogni modo, per prima cosa iniziamo a scrivere un bel programma C:

#include <stdio.h>

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

Abbiamo quindi il nostro programma C, bello grande e corpulento.

Ora per eseguirlo non ci resta altro che compilarlo, assemblarlo, linkarlo e poi, se tutto va bene, eseguirlo.

Compilazione

Con la compilazione otteniamo il nostro caro e vecchio codice assembly; come facciamo ad estrarlo dal nostro codice C?

Non C basta altro che digitare, all'interno di un Terminale il seguente comando:

gcc -S HelloWorld.c	

Quello che otteniamo sarà un nuovo file con estensione .s, che per gli amici, sta per codice assembly; se lo apriamo con un editor vedremo il codice compilato:

	.section	__TEXT,__text,regular,pure_instructions
	.build_version macos, 10, 14	sdk_version 10, 14
	.globl	_main                   ## -- Begin function main
	.p2align	4, 0x90
_main:                                  ## @main
	.cfi_startproc
## %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$16, %rsp
	movl	$0, -4(%rbp)
	leaq	L_.str(%rip), %rdi
	movb	$0, %al
	callq	_printf
	xorl	%ecx, %ecx
	movl	%eax, -8(%rbp)          ## 4-byte Spill
	movl	%ecx, %eax
	addq	$16, %rsp
	popq	%rbp
	retq
	.cfi_endproc
                                        ## -- End function
	.section	__TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
	.asciz	"Hello, World!\n"


.subsections_via_symbols

Questo codice è nettamente più lungo e sopratutto diverso dall'assembly usato con il RISC V, ma se lo osserviamo attentamente potremo notare qualche sezione familiare:

### Stringa da stampare

L_.str:                                 ## @.str
	.asciz	"Hello, World!\n"

Questa parte contiene la nostra stringa da stampare; in RISC V scriviamo:

.data
str1:	.asciz "Hello world!"

Funzione Principale

.globl	_main                   ## -- Begin function main
	.p2align	4, 0x90
_main:                                  ## @main
	.cfi_startproc
	...

In questa sezione notiamo che viene dichiarato che la funzione principale del codice è proprio il main, utilizzando .globl _main;

Anche in RISC V, in modo molto simile, dichiariamo che la funzione principale è il main, utilizzando .globl main

.globl	main
main:	
	la	a0,in_prompt
	li	a7,4
	ecall
	...

Altre somiglianze

Lascio al lettore la ricerca di altre somiglianze perchè io non le trovo 😆.

Assembliamo il tutto

Il prossimo passaggio è assemblare il codice assembly, ed ancora una volta il nostro caro gcc ci torna utile:

gcc -c HelloWorld.c

Otteniamo questo nuovo e strambo file, chiamato helloWorld.o:

������������������ ��������������������������������������������(���������������������������__text����������__TEXT������������������*�������(��������������������������__cstring�������__TEXT����������*��������������R�����������������������������__compact_unwind__LD������������@������� �������h��������������������������__eh_frame������__TEXT����������`�������@�����������������������h������������2����������
��
��������������������������P������������������������������������������������������������������������UH��H���E�����H�=����������1ɉE���H��]�Hello, World!
����������������*�����������������������������zR�x���$��������������*��������A�C
������������-���������������������������������������_main�_printf��

Questo è il famoso codice macchina del nostro programma C.

Però attenzione, questo non è un semplice codice macchina, ma è il codice macchina per la nostra macchina, con il nostro specifico sistema operativo (in questo caso Mac OS).

Ultimo passaggio: il linker

L'ultimo passaggio per poter finalmente eseguire il nostro caro programma C è passare dal linker.

Non ci basterà altro che scrivere sul terminale il comando gcc:

gcc -o helloWorld.c programmaEseguibile

Otterremo così un file programmaEseguibile eseguibile; possiamo lanciarlo con ./nomeprogramma (non lasciare spazi tra './' ed il nome!):

folly$ ./programmaEseguibile 
Hello, World!

Abbiamo così compilato ed eseguito il nostro programma C, passando da assembly fino al linguaggio macchina.

n.b. Non c'è bisogno di seguire tutto il percorso, se hai solo bisogno di compilare ed eseguire un programma C ti basterà digitare gcc -o nomeinput.c nomeOutput, e successivamente ./nomeOutput per eseguirlo!

Trovi tutti i files usati qui!

🏁 00:35

⚠️ **GitHub.com Fallback** ⚠️