Implémentation de strlen() en ASM sur 32 bits

Le problème exposé dans ce sujet a été résolu.

Bonjour,

j’essaie de ré-implémenter strlen en assembleur. Mon ordi est un 64 bits, mais je le fait en 32 bits en compilant avec -m32.

Voici mon code main.c :

#include <stdio.h>
#include <stdlib.h>
int main(int argnb, char* args[]){
    printf("Taile de %s : %d", "bonjour", mstrlen("bonjour"));
    return(0);
}

et mon code assembleur : (mstrlen.s) :

.globl mstrlen

.text

mstrlen:
    movl 4(%esp), %ebx
    movl  $0, %eax
    jmp test
test:
    cmpb $0, (%ebx)
    jne redo
    ret
redo:
    incl %eax
    addl $8,%ebx
    jmp test

.end

L’idée: je met le premier argument 4(%esp) qui est censé être un pointeur vers un str dans ebx. Je met le compteur dans eax. Puis, tant que ebx ne pointe pas vers 0 (fin de chaîne) on ajoute 1 au compteur et 8 (un char) au pointeur. A la fin, on renvoie ; la valeur doit etre dans eax.

Je compile avec : gcc -m32 -g main.c mstrlen.s

Mais quand je teste, j’ai un segfault… Quelqu’un sait pourquoi ?

Merci d’avance !

+0 -0

Hummm, très intéressant tout ça. J’essaye de tout comprendre mais j’ai du mal. La logique du code me semble correcte mais des erreurs dû au fonctionnement bas niveau m’empèche d’avoir autre chose que "segfault" à l’instruction cmpb.

+0 -0

Hummm, très intéressant tout ça. J’essaye de tout comprendre mais j’ai du mal. La logique du code me semble correcte mais des erreurs dû au fonctionnement bas niveau m’empèche d’avoir autre chose que "segfault" à l’instruction cmpb.

ache

Chez moi ça marche.©
En tout les cas en 64 bits.

xstrlen:                            
        .globl  xstrlen
        movq    %rdi, %rbx
        movq    $0, %rax
test:
        cmpb    $0, (%rbx)
        jne     redo
        ret
redo:
        incq    %rax
        incq    %rbx
        jmp     test
#include <stdio.h>                  

extern size_t xstrlen(char *s);


int
main(void)
{
        printf("%zu\n", xstrlen("Test"));
        return 0;
}
$ gcc main.c xstrlen.s -o x
$ ./x
4
+1 -0

Bien vu !

Cependant , même après avoir augmenter ebx de seulement 1, j’ai toujours un segfault…

Après une petite enquête sur gdb, il semble que ce soit au moment où il exécute ret.

Mais je ne vois pas pourquoi, après tout je n’ai pas modifié la pile !?

Petit point bizarre, j’ai essayé de mettre un leave devant ret, je n’ai pas eu de segfault mais le programme a quitté sans rien afficher.

Si vous y comprends quelque chose 😕

EDIT : bon, j’aurais dû lire mon cours plus avant: visiblement i386 utilisé ebx comme "frame pointer". Après l’avoir remplacé par ecx, ça marche bien. Encore merci 😁

+1 -0

Là classe les clémentines !

Bien joué :)

Ça marche effectivement bien chez moi aussi, les deux versions. Faudrait vraiment que je me mettent à l’asm.

+0 -0

Bonjour,

Tu as bien identifié l’origine du problème. Voici un peu plus de précisions.

Le code qui appelle ta fonction s’attend par convention à ce que les valeurs de certains registres dits non-volatiles soient préservées par un appel. Cela fait partie du contrat entre appelant et appelé que l’on appelle «convention d’appel». Si ton code utilise un des registres concernés, il doit stocker (le plus simple étant de stocker sur la pile) sa valeur en entrée de la fonction et la restituer avant le retour vers le code appelant. Dans ton cas, il est suffisant d’utiliser un registre volatile à la place, comme tu l’as fait pour résoudre le problème.

Pour de la doc sur le sujet voir par exemple ici (convention CDECL dans ton cas).

+1 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte