Skip to content
| Marketplace
Sign in
Visual Studio Code>Other>ArthurNRJ Theme VSCommunityNew to Visual Studio Code? Get it now.
ArthurNRJ Theme VSCommunity

ArthurNRJ Theme VSCommunity

arthurnrj

|
1 install
| (0) | Free
Says hello when VS Code opens
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

Assembly x86-64 - Corrigés Complets

Table des matières

  1. my_strlen
  2. strlen_rep
  3. parity_check
  4. _start / sys_hello
  5. fix_strcmp
  6. caller_spy
  7. print_bigsum
  8. memory_args
  9. float / double_avg
  10. cat
  11. balanced_brackets
  12. rpn_eval

my_strlen

Prototype : size_t my_strlen(const char *str)

Retourne : La longueur de la chaîne (sans le '\0')

.text
.global my_strlen

my_strlen:
    xor %rax, %rax
.loop:
    cmpb $0, (%rdi)
    je .end
    inc %rax
    inc %rdi
    jmp .loop
.end:
    ret

Ligne par ligne : | Ligne | Instruction | Explication | |-------|-------------|-------------| | 1 | xor %rax, %rax | length = 0 (initialise le compteur) | | 2 | cmpb $0, (%rdi) | Compare le caractère courant avec '\0' | | 3 | je .end | Si c'est '\0', on a fini | | 4 | inc %rax | length++ | | 5 | inc %rdi | Avance au caractère suivant | | 6 | jmp .loop | Continue la boucle | | 7 | ret | Retourne length |


strlen_rep

Prototype : size_t strlen_rep(const char *str)

Retourne : La longueur de la chaîne en utilisant repne scasb

.text
.global strlen_rep

strlen_rep:
    mov %rdi, %rcx
    xor %al, %al
    mov $-1, %rcx
    repne scasb
    not %rcx
    dec %rcx
    mov %rcx, %rax
    ret

Ligne par ligne : | Ligne | Instruction | Explication | |-------|-------------|-------------| | 1 | mov %rdi, %rcx | Sauvegarde (pas nécessaire ici, erreur corrigée ci-dessous) | | 2 | xor %al, %al | al = 0 (on cherche le '\0') | | 3 | mov $-1, %rcx | rcx = 0xFFFFFFFFFFFFFFFF (max iterations) | | 4 | repne scasb | Répète tant que *rdi != al et rcx != 0 | | 5 | not %rcx | Inverse les bits de rcx | | 6 | dec %rcx | Enlève 1 (le '\0' ne compte pas) | | 7 | mov %rcx, %rax | Met le résultat dans rax | | 8 | ret | Retourne la longueur |

Version corrigée :

.text
.global strlen_rep

strlen_rep:
    xor %al, %al
    mov $-1, %rcx
    repne scasb
    not %rcx
    dec %rcx
    mov %rcx, %rax
    ret

Explication du calcul :

  • rcx commence à -1 (0xFFFF...)
  • À chaque scasb, rcx--
  • Si on trouve '\0' après 5 caractères, rcx = -1 - 5 - 1 = -7
  • not(-7) = 6, dec(6) = 5 ✓

parity_check

Prototype : int parity_check(uint64_t n)

Retourne : 1 si nombre pair de bits à 1, 0 sinon

.text
.global parity_check

parity_check:
    xor %eax, %eax
    popcnt %rdi, %rcx
    test $1, %cl
    setz %al
    ret

Ligne par ligne : | Ligne | Instruction | Explication | |-------|-------------|-------------| | 1 | xor %eax, %eax | result = 0 | | 2 | popcnt %rdi, %rcx | Compte le nombre de bits à 1 dans n | | 3 | test $1, %cl | Teste si le compte est impair | | 4 | setz %al | al = 1 si ZF=1 (count pair), sinon 0 | | 5 | ret | Retourne le résultat |

Alternative sans popcnt :

.text
.global parity_check

parity_check:
    xor %eax, %eax
.loop:
    test %rdi, %rdi
    jz .done
    mov %rdi, %rcx
    and $1, %ecx
    xor %ecx, %eax
    shr $1, %rdi
    jmp .loop
.done:
    xor $1, %eax
    ret

_start / sys_hello

But : Afficher "Hello, World!\n" sans utiliser la libc

.section .rodata
msg: .string "Hello, World!\n"
msg_len = . - msg - 1

.text
.global _start

_start:
    mov $1, %rax
    mov $1, %rdi
    lea msg(%rip), %rsi
    mov $msg_len, %rdx
    syscall

    mov $60, %rax
    xor %rdi, %rdi
    syscall

Ligne par ligne : | Ligne | Instruction | Explication | |-------|-------------|-------------| | 1 | mov $1, %rax | Syscall numéro 1 = write | | 2 | mov $1, %rdi | File descriptor 1 = stdout | | 3 | lea msg(%rip), %rsi | Adresse du message (PIC) | | 4 | mov $msg_len, %rdx | Longueur du message | | 5 | syscall | Appelle write(1, msg, len) | | 6 | mov $60, %rax | Syscall numéro 60 = exit | | 7 | xor %rdi, %rdi | Code de sortie = 0 | | 8 | syscall | Appelle exit(0) |

Compilation : gcc -nostdlib -o sys_hello sys_hello.S


fix_strcmp

Prototype : int fix_strcmp(const char *s1, const char *s2)

Retourne : < 0 si s1 < s2, 0 si égaux, > 0 si s1 > s2

.text
.global fix_strcmp

fix_strcmp:
.loop:
    movzbl (%rdi), %eax
    movzbl (%rsi), %ecx
    cmp %cl, %al
    jne .diff
    test %al, %al
    jz .equal
    inc %rdi
    inc %rsi
    jmp .loop
.diff:
    sub %ecx, %eax
    ret
.equal:
    xor %eax, %eax
    ret

Ligne par ligne : | Ligne | Instruction | Explication | |-------|-------------|-------------| | 1 | movzbl (%rdi), %eax | Charge s1[i] avec zero-extend | | 2 | movzbl (%rsi), %ecx | Charge s2[i] avec zero-extend | | 3 | cmp %cl, %al | Compare les deux caractères | | 4 | jne .diff | Si différents, calcule la différence | | 5 | test %al, %al | Teste si on est à '\0' | | 6 | jz .equal | Si '\0', les chaînes sont égales | | 7-8 | inc %rdi/rsi | Avance dans les deux chaînes | | 9 | jmp .loop | Continue | | 10 | sub %ecx, %eax | Retourne s1[i] - s2[i] | | 11 | xor %eax, %eax | Retourne 0 (égaux) |


caller_spy

Prototype : void *caller_spy(void)

Retourne : L'adresse de retour de la fonction appelante

.text
.global caller_spy

caller_spy:
    mov (%rsp), %rax
    ret

Ligne par ligne : | Ligne | Instruction | Explication | |-------|-------------|-------------| | 1 | mov (%rsp), %rax | Lit l'adresse de retour sur la pile | | 2 | ret | Retourne cette adresse |

Explication :

  • Quand on appelle une fonction, call push l'adresse de retour sur la pile
  • À l'entrée de la fonction, (%rsp) contient cette adresse
  • On la retourne simplement

Version avec offset (pour récupérer l'appelant de l'appelant) :

.text
.global caller_spy

caller_spy:
    mov 8(%rsp), %rax
    ret

print_bigsum

Prototype : void print_bigsum(const char *a, const char *b)

But : Additionne deux grands nombres (chaînes) et affiche le résultat

.section .bss
buffer: .space 1024

.text
.global print_bigsum

print_bigsum:
    push %rbx
    push %r12
    push %r13
    push %r14
    push %r15
    sub $8, %rsp

    mov %rdi, %r12
    mov %rsi, %r13

    mov %rdi, %rdi
    call strlen
    mov %rax, %r14

    mov %r13, %rdi
    call strlen
    mov %rax, %r15

    lea buffer(%rip), %rbx
    add $1022, %rbx
    movb $0, 1(%rbx)
    movb $10, (%rbx)

    xor %ecx, %ecx

.loop:
    xor %eax, %eax
    xor %edx, %edx

    cmp $0, %r14
    jle .skip_a
    dec %r14
    movzbl (%r12, %r14), %eax
    sub $'0', %eax
.skip_a:
    cmp $0, %r15
    jle .skip_b
    dec %r15
    movzbl (%r13, %r15), %edx
    sub $'0', %edx
.skip_b:
    add %edx, %eax
    add %ecx, %eax

    xor %ecx, %ecx
    cmp $10, %eax
    jl .no_carry
    sub $10, %eax
    mov $1, %ecx
.no_carry:
    add $'0', %eax
    dec %rbx
    mov %al, (%rbx)

    mov %r14, %rax
    or %r15, %rax
    jnz .loop

    test %ecx, %ecx
    jz .print
    dec %rbx
    movb $'1', (%rbx)

.print:
    mov %rbx, %rdi
    call puts

    add $8, %rsp
    pop %r15
    pop %r14
    pop %r13
    pop %r12
    pop %rbx
    ret

Ligne par ligne (parties clés) : | Section | Explication | |---------|-------------| | Sauvegarde registres | %rbx, %r12-15 sont callee-saved | | strlen des deux nombres | Obtient la longueur de chaque nombre | | Buffer setup | Prépare le buffer de sortie (de droite à gauche) | | Loop principale | Additionne chiffre par chiffre avec retenue | | Retenue finale | Ajoute '1' si carry restant | | Print | Affiche le résultat |


memory_args

Prototype : Programme _start qui affiche ses arguments

.text
.global _start

_start:
    mov (%rsp), %r12
    lea 8(%rsp), %r13
    xor %r14, %r14

.loop:
    cmp %r12, %r14
    jge .exit

    mov (%r13, %r14, 8), %rdi
    call puts

    inc %r14
    jmp .loop

.exit:
    mov $60, %rax
    xor %rdi, %rdi
    syscall

Ligne par ligne : | Ligne | Instruction | Explication | |-------|-------------|-------------| | 1 | mov (%rsp), %r12 | r12 = argc | | 2 | lea 8(%rsp), %r13 | r13 = &argv[0] | | 3 | xor %r14, %r14 | i = 0 | | 4 | cmp %r12, %r14 | Compare i avec argc | | 5 | jge .exit | Si i >= argc, fin | | 6 | mov (%r13, %r14, 8), %rdi | rdi = argv[i] | | 7 | call puts | Affiche l'argument | | 8 | inc %r14 | i++ | | 9 | jmp .loop | Continue |

Structure de la pile au _start :

(%rsp)      = argc
8(%rsp)     = argv[0] (nom du programme)
16(%rsp)    = argv[1]
24(%rsp)    = argv[2]
...

float / double_avg

Prototype : double double_avg(double *arr, size_t n)

Retourne : La moyenne des éléments du tableau

.text
.global double_avg

double_avg:
    test %rsi, %rsi
    jz .zero

    xorpd %xmm0, %xmm0
    xor %rcx, %rcx

.loop:
    cmp %rsi, %rcx
    jge .divide
    addsd (%rdi, %rcx, 8), %xmm0
    inc %rcx
    jmp .loop

.divide:
    cvtsi2sd %rsi, %xmm1
    divsd %xmm1, %xmm0
    ret

.zero:
    xorpd %xmm0, %xmm0
    ret

Ligne par ligne : | Ligne | Instruction | Explication | |-------|-------------|-------------| | 1-2 | test/jz | Si n=0, retourne 0.0 | | 3 | xorpd %xmm0, %xmm0 | sum = 0.0 | | 4 | xor %rcx, %rcx | i = 0 | | 5-6 | cmp/jge | Si i >= n, calcule la moyenne | | 7 | addsd (%rdi, %rcx, 8), %xmm0 | sum += arr[i] | | 8 | inc %rcx | i++ | | 9 | jmp .loop | Continue | | 10 | cvtsi2sd %rsi, %xmm1 | Convertit n en double | | 11 | divsd %xmm1, %xmm0 | xmm0 = sum / n | | 12 | ret | Retourne la moyenne (dans xmm0) |

Instructions float importantes : | Instruction | Signification | |-------------|---------------| | addsd | Add Scalar Double | | subsd | Subtract Scalar Double | | mulsd | Multiply Scalar Double | | divsd | Divide Scalar Double | | cvtsi2sd | Convert Signed Int to Scalar Double | | cvtsd2si | Convert Scalar Double to Signed Int | | xorpd | XOR Packed Double (pour mettre à 0) |


cat

Prototype : Programme qui implémente cat (lit fichiers et les affiche)

.section .bss
buffer: .space 4096

.text
.global _start

_start:
    mov (%rsp), %r12
    lea 8(%rsp), %r13

    cmp $1, %r12
    jle .read_stdin

    mov $1, %r14

.file_loop:
    cmp %r12, %r14
    jge .exit

    mov (%r13, %r14, 8), %rdi
    xor %esi, %esi
    xor %edx, %edx
    mov $2, %rax
    syscall

    test %rax, %rax
    js .next_file

    mov %rax, %r15

.read_loop:
    mov $0, %rax
    mov %r15, %rdi
    lea buffer(%rip), %rsi
    mov $4096, %rdx
    syscall

    test %rax, %rax
    jle .close_file

    mov %rax, %rdx
    mov $1, %rax
    mov $1, %rdi
    lea buffer(%rip), %rsi
    syscall

    jmp .read_loop

.close_file:
    mov $3, %rax
    mov %r15, %rdi
    syscall

.next_file:
    inc %r14
    jmp .file_loop

.read_stdin:
    mov $0, %r15
    jmp .read_loop

.exit:
    mov $60, %rax
    xor %rdi, %rdi
    syscall

Ligne par ligne (parties clés) : | Section | Explication | |---------|-------------| | mov $2, %rax | Syscall open | | mov $0, %rax | Syscall read | | mov $1, %rax | Syscall write | | mov $3, %rax | Syscall close | | mov $60, %rax | Syscall exit |

Syscalls utilisés : | Numéro | Nom | Arguments | |--------|-----|-----------| | 0 | read | fd, buf, count | | 1 | write | fd, buf, count | | 2 | open | path, flags, mode | | 3 | close | fd | | 60 | exit | code |


balanced_brackets

Prototype : int balanced_brackets(const char *str)

Retourne : 1 si les parenthèses/crochets/accolades sont équilibrés, 0 sinon

.section .bss
stack: .space 1024

.text
.global balanced_brackets

balanced_brackets:
    push %rbx
    push %r12

    mov %rdi, %r12
    lea stack(%rip), %rbx
    xor %ecx, %ecx

.loop:
    movzbl (%r12), %eax
    test %al, %al
    jz .check_empty

    cmp $'(', %al
    je .push
    cmp $'[', %al
    je .push
    cmp $'{', %al
    je .push

    cmp $')', %al
    je .check_paren
    cmp $']', %al
    je .check_bracket
    cmp $'}', %al
    je .check_brace

    inc %r12
    jmp .loop

.push:
    mov %al, (%rbx, %rcx)
    inc %rcx
    inc %r12
    jmp .loop

.check_paren:
    test %rcx, %rcx
    jz .fail
    dec %rcx
    cmpb $'(', (%rbx, %rcx)
    jne .fail
    inc %r12
    jmp .loop

.check_bracket:
    test %rcx, %rcx
    jz .fail
    dec %rcx
    cmpb $'[', (%rbx, %rcx)
    jne .fail
    inc %r12
    jmp .loop

.check_brace:
    test %rcx, %rcx
    jz .fail
    dec %rcx
    cmpb $'{', (%rbx, %rcx)
    jne .fail
    inc %r12
    jmp .loop

.check_empty:
    test %rcx, %rcx
    jnz .fail
    mov $1, %eax
    jmp .done

.fail:
    xor %eax, %eax

.done:
    pop %r12
    pop %rbx
    ret

Ligne par ligne (parties clés) : | Section | Explication | |---------|-------------| | Stack BSS | Pile pour stocker les ouvertures | | .push | Empile le caractère ouvrant | | .check_* | Vérifie que le fermant correspond à l'ouvrant | | .check_empty | À la fin, la pile doit être vide |

Logique :

  1. Parcourt la chaîne caractère par caractère
  2. Si ouvrant ([{ : push sur la pile
  3. Si fermant )]} : pop et vérifie la correspondance
  4. À la fin, pile vide = équilibré

rpn_eval

Prototype : int64_t rpn_eval(const char *expr)

Retourne : Le résultat de l'expression en notation polonaise inversée

Exemple : "3 4 + 2 *" = (3+4)*2 = 14

.section .bss
stack: .space 8192

.text
.global rpn_eval

rpn_eval:
    push %rbx
    push %r12
    push %r13
    push %r14
    push %r15

    mov %rdi, %r12
    lea stack(%rip), %r13
    xor %r14, %r14

.main_loop:
    movzbl (%r12), %eax
    test %al, %al
    jz .end

    cmp $' ', %al
    je .skip

    cmp $'+', %al
    je .add
    cmp $'-', %al
    je .sub_op
    cmp $'*', %al
    je .mul
    cmp $'/', %al
    je .div_op

    xor %rax, %rax
.parse_num:
    movzbl (%r12), %ecx
    sub $'0', %ecx
    cmp $9, %ecx
    ja .push_num
    imul $10, %rax
    add %rcx, %rax
    inc %r12
    jmp .parse_num

.push_num:
    mov %rax, (%r13, %r14, 8)
    inc %r14
    jmp .main_loop

.skip:
    inc %r12
    jmp .main_loop

.add:
    dec %r14
    mov (%r13, %r14, 8), %rax
    dec %r14
    add (%r13, %r14, 8), %rax
    mov %rax, (%r13, %r14, 8)
    inc %r14
    inc %r12
    jmp .main_loop

.sub_op:
    cmp $1, %r14
    jle .parse_negative

    dec %r14
    mov (%r13, %r14, 8), %rbx
    dec %r14
    mov (%r13, %r14, 8), %rax
    sub %rbx, %rax
    mov %rax, (%r13, %r14, 8)
    inc %r14
    inc %r12
    jmp .main_loop

.parse_negative:
    inc %r12
    xor %rax, %rax
.parse_neg_num:
    movzbl (%r12), %ecx
    sub $'0', %ecx
    cmp $9, %ecx
    ja .push_neg
    imul $10, %rax
    add %rcx, %rax
    inc %r12
    jmp .parse_neg_num

.push_neg:
    neg %rax
    mov %rax, (%r13, %r14, 8)
    inc %r14
    jmp .main_loop

.mul:
    dec %r14
    mov (%r13, %r14, 8), %rax
    dec %r14
    imul (%r13, %r14, 8), %rax
    mov %rax, (%r13, %r14, 8)
    inc %r14
    inc %r12
    jmp .main_loop

.div_op:
    dec %r14
    mov (%r13, %r14, 8), %rbx
    dec %r14
    mov (%r13, %r14, 8), %rax
    cqo
    idiv %rbx
    mov %rax, (%r13, %r14, 8)
    inc %r14
    inc %r12
    jmp .main_loop

.end:
    dec %r14
    mov (%r13, %r14, 8), %rax

    pop %r15
    pop %r14
    pop %r13
    pop %r12
    pop %rbx
    ret

Ligne par ligne (parties clés) : | Section | Explication | |---------|-------------| | .parse_num | Parse un nombre et le push | | .add | Pop 2 valeurs, additionne, push résultat | | .sub_op | Pop 2 valeurs, soustrait, push résultat | | .mul | Pop 2 valeurs, multiplie, push résultat | | .div_op | Pop 2 valeurs, divise, push résultat | | .end | Retourne le sommet de la pile |

Algorithme RPN :

  1. Si c'est un nombre → push sur la pile
  2. Si c'est un opérateur → pop 2 opérandes, calcule, push résultat
  3. À la fin → le résultat est sur le sommet de la pile

Note sur cqo :

  • cqo = Convert Quadword to Octword
  • Étend le signe de %rax vers %rdx:%rax
  • Nécessaire avant idiv pour la division signée

Rappels importants

Registres pour les arguments (System V AMD64 ABI)

Argument Registre
1er %rdi
2ème %rsi
3ème %rdx
4ème %rcx
5ème %r8
6ème %r9
Retour %rax
Float args %xmm0-%xmm7
Float return %xmm0

Registres callee-saved vs caller-saved

Callee-saved (à préserver) Caller-saved (volatiles)
%rbx %rax
%rbp %rcx
%r12 %rdx
%r13 %rsi
%r14 %rdi
%r15 %r8-%r11

Syscalls Linux x86-64

Numéro Nom rdi rsi rdx
0 read fd buf count
1 write fd buf count
2 open path flags mode
3 close fd - -
60 exit code - -
  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft