IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

x86 32-bits / 64-bits Assembleur Discussion :

syscall getpid, valeur de retour ?


Sujet :

x86 32-bits / 64-bits Assembleur

  1. #1
    Futur Membre du Club
    Inscrit en
    Mars 2009
    Messages
    14
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 14
    Points : 7
    Points
    7
    Par défaut syscall getpid, valeur de retour ?
    Bonjour,

    Je commence tout juste à apprendre l'assembleur (depuis hier) et je fais donc mumuse avec pour me familiariser avec le langage.
    Je suis sous Linux et utilise Nasm. Architecture x86, 32bits, syntaxe Intel.

    Voici mon code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    ;getpid.asm
    [SECTION .txt]
    global _start
    _start:
     
        xor eax, eax    ; eax à 0
        mov al, 20      ; syscall getpid
        int 0x80         ; execute
     
        push eax        ; met sur la stack la valeur retroune par getpid
        xor eax, eax    ; eax à 0
        xor ebx,ebx    ; ebx à 0
        xor ecx, ecx    ; idem
        xor edx, edx    ; idem
        mov al, 4   ; syscall write
        mov bl, 1   ; stdout 1 dans ebx
        mov ecx, esp    ; positionne ecx sur le haut de ma stack donc la valeur de retour de getpid
        mov dl, 4   ; longueur de la valeur
        int 0x80    ; execute
     
        xor eax, eax    ; eax à 0
        xor ebx, ebx    ; pour mettre un 0 dans exit
        mov al, 1   ; syscall exit
        int 0x80    ; execute
    Déjà, je ne sais pas si le code est bon. Il se compile mais ne m'affiche rien ou des caractères bizarres.
    J'aimerais pourvoir afficher à l'écran la valeur de retour de getpid qui est normalement par exemple : 3889

    Si je fais :

    j'obtiens par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    getpid()               = 3890
    write(1, "2\17\0\0", 42)    = 4
    _exit(0)                = ?
    J'ai l'impression que j'écrase le troisième argument de write..

    Pouvez-vous m'aider ?

  2. #2
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 452
    Points : 43 099
    Points
    43 099
    Par défaut
    getpid te retourne le numéro de PID dans eax que l'on peut voir comme un entier 32 bits.

    write affiche les caractères présents à l'adresse passée en ecx de mémoire. Par ailleurs il te faut convertir la valeur dans eax en chaine de caractères. ton numéro de pid va être considéré comme une adresse mémoire.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  3. #3
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    salut,

    déjà considères que si tu push il te faut créer une stack frame, en pratique ça risque pas grand chose mais c'est une habitude à prendre

    ta stack locale est bornée par esp en haut et ebp en bas (attentions en regardant leurs valeurs c'est le contraire, la pile "grandit vers le bas"), le principe est simple, ebp qui était en bas on le met en haut, et on recule esp pour définir une nouvelle frame

    c'est un classique :
    Code nasm : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ; début du code - prologue
    push ebp      ; on sauvegarde l'ebp sur la pile
    mov ebp, esp  ; on déplace ebp sur le haut de l'ancienne frame == le bas de la nouvelle
    sub esp, 100  ; la pile grandit vers le bas donc on soustrait 100 octets à esp pour nous faire une frame plus que suffisante
     
    (...)
     
    ; fin du code (ou plus exactement sortie de la fonction principale) - épilogue
    leave  ; l'instruction leave détruit la frame, c'est équivalent à mov esp, ebp suivi de pop ebp, soit l'inverse du prologue
    ret


    Citation Envoyé par blackndoor Voir le message
    j'obtiens par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    getpid()               = 3890
    write(1, "2\17\0\0", 42)    = 4
    _exit(0)                = ?
    c'est plutôt une bonne nouvelle, ça veut dire que le programme s’exécute et que tu t'es pas trompé dans l'appel de tes syscalls

    Citation Envoyé par blackndoor Voir le message
    Déjà, je ne sais pas si le code est bon. Il se compile mais ne m'affiche rien ou des caractères bizarres.
    J'aimerais pourvoir afficher à l'écran la valeur de retour de getpid qui est normalement par exemple : 3889
    héhé... au retour de sys_getpid(), c'est eax qui contient la valeur du pid, mais eax c'est un registre, pas une string idem pour ton sys_write(), c'est pas comme printf(), tu n'as pas de chaine de format ici

    à partir de là y'a deux écoles, soit tu invoques printf() et il va falloir habiller ton code pour qu'il puisse coopérer et compiler avec la libc, soit tu codes toi même une routine de conversion... autant dire qu'on prend vite gout à lire l'hexadécimal plutôt que le décimal
    l'avantage c'est que tu as désormais une belle stackframe de 100 octets pour stocker tout ce que tu veux

    edit: pris de vitesse par chrtophe ^^

  4. #4
    Futur Membre du Club
    Inscrit en
    Mars 2009
    Messages
    14
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 14
    Points : 7
    Points
    7
    Par défaut
    Merci pour vos réponses.

    Effectivement, il faudrait que je convertisse le retour de sys_getpid(), qui est en hexa, en ascii.
    Il y a quelques exemples sur le net mais je m'y perds un peu..

    Je suis partie sur l'option d'utiliser printf.
    Voici mon code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    ;getpid.asm
    extern	printf
     
    SECTION .data
    	msg: db "PID= %x",10,0
     
    SECTION .text
    global main
    main:
     
    	push ebp	; pose ebp sur la stack
    	mov ebp, esp	; positionne ebp au niveau de esp
    	sub esp, 100	; augmente esp
     
    	xor eax, eax	; eax à 0
    	mov al, 20	; syscall getpid
    	int 0x80	; execute
     
    	push eax 	; pose le retour de sys_getpid sur la stack
    	push dword [msg]	; pose mon message sur la stack
    	call printf                  ; appel de printf
    	add esp, 8                ; diminue esp de 8 car deux push
     
    	leave		; détruit la stack
     
    	xor eax, eax	;
    	xor ebx, ebx	; pour exit (0)
    	mov al, 1	; syscall  exit
    	int 0x80	; execute
    Je compile avec :
    nasm -f elf getpid.asm
    gcc -o getpid getpid.o

    Puis avec strace :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    getpid()                                = 6719
    --- SIGSEGV (Segmentation fault) @ 0 (0) ---
    +++ killed by SIGSEGV +++
    Erreur de segmentation
    Erreur malheureusement. Le problème vient je pense de l'appel à printf mais je ne vois pas ce qui cloche.
    printf("pid: %x", 0x30B) fonctionne normalement.

  5. #5
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    Citation Envoyé par blackndoor Voir le message
    Erreur malheureusement. Le problème vient je pense de l'appel à printf mais je ne vois pas ce qui cloche.
    push dword msg sans les crochets, tout simplement

  6. #6
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 452
    Points : 43 099
    Points
    43 099
    Par défaut
    push dword msg sans les crochets, tout simplement
    va "pusher" msg sur la pile
    va "pusher" le contenu de msg sur la pile, d’où le segfault car le contenu que tu pushe correspond aux 4 premiers octets de msg (32 bits =dword) qui est traitée comme une adresse invalide.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  7. #7
    Futur Membre du Club
    Inscrit en
    Mars 2009
    Messages
    14
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 14
    Points : 7
    Points
    7
    Par défaut
    Merci pour vos réponses.

    Effectivement, cela fonctionne mieux sans les crochets et c'est logique comme il faut que je donne l'adresse mémoire et non le contenu.

    Auriez-vous un bon lien pour convertir de l'hex en décimale ? Je trouve pas ce que je veux à se sujet.

  8. #8
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    salut,

    pas de lien sous la main mais construire une petite routine n'est pas très difficile il suffit de réfléchir un peu

    une façon de faire repose sur un principe simple, l'instruction div en assembleur effectue une division entière, quotient se retrouve ensuite dans eax tandis que le reste va dans edx, on veut afficher en décimal donc un système à base 10

    prenons par exemple la valeur 1337, tant que le quotient sera différent de 0 on continuera de lui faire subir des divisions et on conservera le reste :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     1337 div 10 ==> eax: 133    edx: 7
      133 div 10 ==> eax: 13     edx: 3
       13 div 10 ==> eax: 1      edx: 3
        1 div 10 ==> eax: 0      edx: 1
    bien sur il faudra penser pour chaque reste (7,3,3,1) à le stocker quelque part, dans le bon ordre, et pour chaque chiffre ne pas oublier de lui rajouter 0x30 pour l'affichage (voir la table ASCII)

    l'implémentation est laissée en exercice

  9. #9
    Futur Membre du Club
    Inscrit en
    Mars 2009
    Messages
    14
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 14
    Points : 7
    Points
    7
    Par défaut
    merci pour ta réponse.

    Donc si je comprends bien et avec l'exemple suivant : 0B

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    OB div 10 ==> eax:1  edx:1
    1  div 10 ==> eax:0  edx:1
    Correct ?

  10. #10
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    je sais pas, d'après toi ? ça a l'air de le faire ou pas ?

  11. #11
    Futur Membre du Club
    Inscrit en
    Mars 2009
    Messages
    14
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 14
    Points : 7
    Points
    7
    Par défaut
    franchement, je me perds...

    Voici un code test :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    ;getpid.asm
    SECTION .bss
            pid: resb 2
            pidlen: equ $-pid
     
    SECTION .text
    global _start
    _start:
     
    	xor eax, eax
    	xor ebx, ebx
    	xor ecx, ecx
    	xor edx, edx
     
    	mov ax, 0x0b
    	mov bx, 10
    	div bx
    	mov cx, ax
    	mov ax, dx
    	div bx
    	push cx
    	push dx
    	pop eax
    	add ax, 30h
    	mov [pid], ax
    	xor eax, eax,
    	xor ebx, ebx
    	xor ecx, ecx
    	xor edx, edx
    	mov al, 4
    	mov bl, 1
    	mov dl, pidlen
    	push dword pid
    	pop ecx
    	int 0x80
     
    	xor eax, eax
    	xor ebx, ebx
    	mov eax, 1
    	int 0x80
    La sortie m'affiche : 7
    Donc 37h

    J'aimerai pouvoir suivre mes registres dans gdb mais je n'arrive pas à mettre de point d'arrêt

  12. #12
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    salut,

    alors pour être honnête, c'est pas que je voulais pas reprendre ton code mais sans aucun commentaire... c'est de l'ASM quand même

    du coup je te propose ce code, commenté, libre à toi de le repomper tel quel ou non, et si t'as des questions hésites évidemment pas :
    Code nasm : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    ; ---------------------------
    ; getpid.asm
    ; ---------------------------
    ; compile:
    ;    nasmf -f elf getpid.asm
    ;    ld -o getpid getpid.o
    ; ---------------------------
     
    %define SYS_EXIT    1   ; void exit(int code)
    %define SYS_WRITE   4   ; int write(int fd, char* str, int len)
    %define SYS_GETPID  20  ; int getpid(void)
     
    SECTION .text
        global _start
     
    _start:
        ; prologue
        push ebp
        mov ebp, esp
        sub esp, 12     ; on reserve 12 octets sur la pile, ca devrait etre suffisant pour afficher un pid
     
        ; on récupère le pid
        mov eax, SYS_GETPID
        int 0x80
     
        ; generation de la string contenant le pid %d
        mov ebx, 10     ; on set le dénominateur
        mov edi, ebp    ; plutot que de stocker coté esp comme ferait un push, on stocke à l'opposé de la pile, coté ebp, en remontant vers esp
     
            ;    -------------------------------------------------------------------------------------------------------------------
            ;   [        |        |        |        |       |   T4   |   T3   |   T2   |   T1   |   T0   |   \n   |  0x00  |  0x11  ]
            ;    -------------------------------------------------------------------------------------------------------------------
            ;   ^                                           ^                                                                       ^
            ;   esp                                    <-- edi                                                                    ebp
            ;
            ; push recule (modifie) esp                                                     <-- nous on va dans ce sens en partant de ebp, à chaque
            ; pop le re-avance vers ebp                                                         tour de boucle Tx on stocke un chiffre et on recule
            ;                                                                                   notre pointeur edi à l'intérieur de la stack frame
     
        sub edi, 4      ; on se place sur le dword précédent pour pas écraser ebp
        mov dword [edi], 0x11000aFF ; valeur a la gomme juste pour illustrer, à l'endroit de [edi] il y a FF, puis '\n', suivi de '\0', la fin de notre string
        mov ecx, 1      ; on a deja au minimum 1 caractère à afficher: le '\n' à la fin
        std             ; on modifie l'indicateur de direction pour aller en sens inverse avec edi lors du stosb plus bas
    _l1:      ; la boucle principale
        div ebx         ; edx=0, eax contient le numérateur, le dénom. est toujours dans ebx => on recup quotient dans eax, et le reste dans edx
        add edx, 0x30   ; on rend le reste "printable" (cf table ASCII)
        xchg eax, edx   ; -- <petite manip, on echange les deux registres>
        stosb           ; ici on profite du fait qu'on ecrit al directement dans es:[edi], et edi se décrémente tout seul (grace au flag de direction)
        xchg eax, edx   ; -- </fin de l'embrouille, on remet comme c'etait>
        xor edx, edx    ; on remet edx (partie haute du numérateur) à 0
        inc ecx         ; on incrémente notre compteur de lettres à afficher
        test eax, eax   ; est-ce que le quotient vaut 0 ?
        jnz _l1
        inc edi         ; on pointe sur le debut de notre string juste un octet trop loin, toujours a cause du stosb
        cld             ; on remet l'indicateur de direction à 0
     
        ; on affiche
        mov eax, SYS_WRITE
        mov ebx, 1      ; STDOUT_FILENO
        mov edx, edi    ; la string représentant le pid
        xchg ecx, edx   ; on hop, on remet dans l'ordre c'est magique
        int 0x80
     
        ; on passe le balais vite fait
        leave
     
        ; on ferme à clé et on s'en va
        mov eax, SYS_EXIT
        xor ebx, ebx
        int 0x80

    Citation Envoyé par blackndoor Voir le message
    J'aimerai pouvoir suivre mes registres dans gdb mais je n'arrive pas à mettre de point d'arrêt
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    break *_start
    b *_start
    b *(_start + 0d13)   # note le 'd' pour décimal, attention donc parceque "53" par défaut est considéré comme "0x53"
    b *(_start + 0x22)
    b *0x08048085
    b *$eax
    (...)

  13. #13
    Invité
    Invité(e)
    Par défaut
    Salut,

    L'idée de convertir un nombre stocké en format binaire 32-bit en ASCII est détaillé
    avec un exemple ici: http://asm.developpez.com/cours/gas/#LV-A.

    Attention! le code est écris en assembleur GNU et non en NASM!

  14. #14
    Membre régulier
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Avril 2015
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2015
    Messages : 46
    Points : 108
    Points
    108
    Par défaut
    Bonsoir,

    Il existe plusieurs stratégies pour transformer du binaire/hex en string.
    J'en ai quelques unes en stock ici https://github.com/netmonk/asm/ pour de l'assembleur nasm sous linux 64bits.
    En particulier :*
    - division par 10
    - soutraction de puissance de 10
    - addition de puissance de 2

Discussions similaires

  1. Valeur de retour d'une procédure stockée
    Par Rudyweb dans le forum MFC
    Réponses: 4
    Dernier message: 25/02/2005, 17h52
  2. fonction operator, valeur de retour
    Par butch dans le forum C++
    Réponses: 21
    Dernier message: 20/09/2004, 10h30
  3. [VB6] Valeur de retour pour une Form
    Par preverse dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 17/08/2004, 17h16
  4. Valeur de retour d'une procédure externe
    Par elekis dans le forum x86 32-bits / 64-bits
    Réponses: 4
    Dernier message: 16/04/2004, 16h45
  5. Pourquoi une seule valeur de retour pour les fonctions ?
    Par Bruno75 dans le forum Langages de programmation
    Réponses: 33
    Dernier message: 18/01/2004, 13h58

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo