[linux] read and open

sheorogath Messages postés 2448 Date d'inscription samedi 21 février 2004 Statut Modérateur Dernière intervention 29 janvier 2010 - 18 juil. 2006 à 01:14
_dune2_ Messages postés 141 Date d'inscription mercredi 19 juillet 2006 Statut Membre Dernière intervention 20 avril 2011 - 28 juil. 2006 à 14:28
Bonjour,
je débute un peu en assembleur et j'essaie de faire un programme qui lit le début d'un fichier dont le nom est entré par l'utilisateur.

Voici le code :
; Instruction de compilation :
; nasm -f elf dcat.asm
; ld -o dcat dcat.o

segment .data                ; variables initialisées constantes
    buflen: dd 254
    readlen: dd 254
    err: dd 128

    error:     db 'error open',10   
    errorLen:  equ $-error   
segment .bss
    buf:        resb    254
    read:    resb    254
    lerr: resb 128
segment .text                ; équivalent de main() mais c'est pas une fonction
    global _start

errorf:        ;si on ne peut pas ouvrir le fichier
   
    mov eax,4                  ;syscall 4 => write
    mov ebx,1                  ;1 => STDOUT
    mov ecx,error            ;what ? error
    mov edx,errorLen     ;length? errorLen   
    int 80h                        ;execute

    mov eax,1                ;syscall 1 => exit
    mov ebx,0                ;error code => 0
    int 80h                     ;execute
    ret                            ;end

readf:        ;si on a ouvert le fichier
   
    mov ebx,eax            ; move file descriptor in ebx
    mov eax,3                ;syscall 3 => read
    mov ecx,read          ;put in read
    mov edx,readlen    ;length
    int 80h                    ;execute

    mov eax,4                ;syscall 4 => write
    mov ebx,1                ;where? STDOUT
    int 80h                ;execute
                                ;ecx , edx already defined
    mov eax,1                ;syscall 1 => exit
    mov ebx,0                ;error code
    int 80h                 ;execute
    ret                        ;exit

_start:                    ; programme en lui même
   
    mov eax,3               ;syscall 3 => read
    mov ebx,0               ; Where? STDIN
    mov ecx,buf            ;save in buf
    mov edx,buflen       ;length of buf
    int 80h                     ;execute

    mov eax,5                ;syscall 5 => open
    mov ebx,buf            ;open what ?buf
    mov ecx,0                ;flag => read only
    int 80h                     ;execute
   
    test    eax,-1             ; an error ?
    je    errorf                 ;yes jump to error
    jne    readf                ;no read file
   

Je n'ai aucune sortie comme quoi le fichier n'existe pas (qu'il existe ou pas d'ailleurs).
Enfin bref je ne sais pas où est mon erreur.
Pouvez-vous m'aider ou me mettre sur la voie ?

Merci
++

"n'est pas mort ce qui semble a jamais dormir et en d'etrange temps meme la mort peut mourrir"

6 réponses

cs_Nasman Messages postés 202 Date d'inscription mardi 17 mai 2005 Statut Membre Dernière intervention 29 septembre 2008 3
18 juil. 2006 à 10:03
Bonjour,

Je ne connais pas les fonctions système de linux, aussi juste une question.
Quels sont les registres modifiés par l'appel de la fonction système 3. En clair es tu sur que les registres ecx et edx contiennent toujours les bonnes valeur lors de l'appel à la fonction syscall 4.


Autre chose : utilisant Nasm pour windows je ne sais pas quelle est la déclaration pour linux pour indiquer le point d'entrée du programme. Est-ce que nasm reconnait _start:  comme point d'entrée ?

A+
0
sheorogath Messages postés 2448 Date d'inscription samedi 21 février 2004 Statut Modérateur Dernière intervention 29 janvier 2010 17
18 juil. 2006 à 13:43
pour le point d'entree il n'y a pas de probleme
sinon pour les registre en fait quand je passe sur open eax a toujours la meme valeur 0xFFFFFFFe que le fichier existe ou pas dailleur et je ne vois pas pourquoi
"n'est pas mort ce qui semble a jamais dormir et en d'etrange temps meme la mort peut mourrir"
0
cs_patatalo Messages postés 1466 Date d'inscription vendredi 2 janvier 2004 Statut Modérateur Dernière intervention 14 février 2014 2
22 juil. 2006 à 18:11
salut,




test eax,-1 sera toujours vrai sauf si eax=0 (c'est un "et logique" sans modification des flags), tu devrais plutot faire:
cmp eax,-1
je error
jmp ok

@++
0
sheorogath Messages postés 2448 Date d'inscription samedi 21 février 2004 Statut Modérateur Dernière intervention 29 janvier 2010 17
23 juil. 2006 à 12:29
ok merci beaucoup
un debut de reponse ;)

"n'est pas mort ce qui semble a jamais dormir et en d'etrange temps meme la mort peut mourrir"
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
_dune2_ Messages postés 141 Date d'inscription mercredi 19 juillet 2006 Statut Membre Dernière intervention 20 avril 2011
27 juil. 2006 à 14:32
Bon, aprés quelques essais, j'ai trouvé quelques points interessants :


1) lors du "open", 2 problèmes sont à signaler :

  1: le mode d'ouverture doit inclure O_CREAT en plus de O_RDWR
pour créer le fichier s'il n'existe pas ce qui fait qu'il faut mettre
102 dans ECX (O_CREAT=100 | O_RDWR=2)

  2: en cas de création du fichier, il faut bien entendu spécifier
les droits du fichier dans EDX, dans notre cas je suggère 0666
-rw-rw-rw- (attention à la notation Octal : 0666 et non 666).


2) lors de la saisie du nom de fichier, il faut retirer le "\n" ajouté
au clavier lors de la saisie, sinon celui-ci fera parti du nom du
fichier (ajout de "?" à la fin du nom du fichier, gênant pour toutes
manipulations).


3) L'utilisation de "cmp" est destructif sur EAX, et le CPU crée un
EAX_ORIG (registre temporaire pour sa sauvegarde) ce qui fait qu'on ne
teste pas le registre EAX comme on s'y attend. Il faut donc utiliser
l'instruction "test" non destructif, et se servir du flag "sign" pour
detecter une valeur négative. ("test eax,eax ; js _failure").


4) Penser à faire un syscall à "close" pour bien terminer ;)


Voici le code (en asm AT&T) incorporant ces modifications et fonctionnel :

// compile with as :

// as readAndWrite.s -o readAndWrite.o ( add -g for debug)

// link with ld :

// ld readAndWrite.o -o readAndWrite ( add -g for debug )


.section    .data

inputname:    .string "Nom du fichier : "

errorstr:    .string "Unable to open file !\n"

puttext:    .string "Enter text now :\n"

filename:    .space  256

buffer:        .space    1024

fdfile:        .long    0


.section    .text

.global        _start

 

_start:

           
           
           
    // Write enter filename

    mov       
$4,%eax;           
        // syscall 4 = write

    mov       
$1,%ebx;           
        // filedesc 1 = STDOUT

    mov       
$inputname,%ecx;       
    // @inputname

    mov     $(errorstr-inputname),%edx;    // strlen ( inputname )

    int       
$0x80;           
            // syscall


_readfilename:           
           
    // read the filename

    mov       
$3,%eax;           
        // syscall 3 = read

    mov       
$0,%ebx;           
        // filedesc 0 = STDIN

    mov       
$filename,%ecx;           
    // @filename

    mov     $(buffer-filename),%edx;    // strlen ( chaine )

    int       
$0x80;           
            // syscall


_removeCRonfilename:       
            // we need to
remove the CR of filename

    mov    
$filename,%ecx;           
    // we know that read return number of characters in
EAX

    add     %eax,%ecx;   
           
    // so we use it to locate the CR

    dec       
%ecx;           
            // the
character just before the end :)

    movb    $0,(%ecx);   
           
    // put null character in place (carefull we put a
byte,

           
           
           
    //  it is why we add 'b' to 'mov' -> 'move
byte')


_openfile:           
           
        // open the filename

    mov       
$5,%eax;           
        // syscall 5 = open

    mov       
$filename,%ebx;           
    // @filename

    mov       
$102,%ecx;           
        // flags O_RDWR=2 | O_CREAT=100
!!!

    mov     $0666,%edx;   
           
    // mode default & open_mask

    int       
$0x80;           
            // syscall

   

_checkopen:           
           
        // check if open is OK

    test    %eax,%eax;   
           
    // check EAX sign

    js       
_failure;           
        // On error (sign flag) , go to
_failure

    mov       
%eax,fdfile;           
    // put fdfile at @fdfile


_writeokmessage:       
           
    // Write input text

    mov       
$4,%eax;           
        // syscall 4 = write

    mov       
$1,%ebx;           
        // filedesc 1 = STDOUT

    mov       
$puttext,%ecx;           
    // @chaine

    mov     $(filename-puttext),%edx;    // strlen ( chaine )

    int       
$0x80;           
            // syscall


_readstdin:           
           
        // read stdin to buf

    mov       
$3,%eax;           
        // syscall 3 = read

    mov       
$0,%ebx;           
        // filedesc 0 = STDIN

    mov       
$buffer,%ecx;           
    // @buffer

    mov     $(fdfile-buffer),%edx;        // strlen ( buffer )

    int       
$0x80;           
            // syscall


_writeinfile:           
           
    // write buf in file

    mov       
$4,%eax;           
        // syscall 4 = write

    mov       
fdfile,%ebx;           
    // get fdfile in EBX

    mov       
$buffer,%ecx;           
    // @buffer

    mov     $(fdfile-buffer),%edx;        // strlen ( buffer )

    int       
$0x80;           
            // syscall


_closefile:           
           
        // close file

    mov       
$6,%eax;           
        // syscall 6 = close

    mov       
fdfile,%ebx;           
    // get fdfile in EBX

    int       
$0x80;           
            // syscall


_end:

    mov       
$1,%eax;           
        // syscall 1 = exit

    mov     $0,%ebx;   
           
    // return code = 0

    int     $0x80;   
           
        // syscall

   

_failure:           
           
        // Write Failure

    mov       
$4,%eax;           
        // syscall 4 = write

    mov       
$2,%ebx;           
        // filedesc 2 = STDERR

    mov       
$errorstr,%ecx;           
    // @chaine

    mov     $(puttext-errorstr),%edx;    // strlen ( chaine )

    int       
$0x80;           
            // syscall


_endfailed:

    mov       
$1,%eax;           
        // syscall 1 = exit

    mov     $-1,%ebx;   
           
    // return code = -1

    int     $0x80;   
           
        // syscall

   


L'ajout des labels à chaque opération m'ont permis de pouvoir mettre
des breakpoints à chaque étape importante lors du débugage avec gdb et
même Eclipse (qui supporte au passage la coloration syntaxique de
AT&T ;) ).


NB: juste une petite explication sur les principales différences entre asm Intel et AT&T pour une meilleure compréhension:

- les opérandes sont inversées : la destination est toujours la dernière opérande en AT&T

- les registres sont toujours précédés par '%'

- les variables qui commencent par '$' sont des valeurs immédiates, sinon, ce sont des adresses qui pointent sur la valeur.

- les valeurs immédiates sont toujours précédés de '$' et la notation
numérique est celle du C : $0x45 (hexa) $45 (decimal) $045 (octal)


Voilà .. je pense que ce doit être suffisent pour comprendre le source ...


Dune2.

Gentoo... que du bonheur ...
0
_dune2_ Messages postés 141 Date d'inscription mercredi 19 juillet 2006 Statut Membre Dernière intervention 20 avril 2011
28 juil. 2006 à 14:28
Salut tout le monde,


Je viens de trouver un détail sur le code précedent, sur la partie :

_readstdin:   
           
           
    // read stdin to buf
   
mov        $3,%eax;   
           
    // syscall 3 = read
   
mov        $0,%ebx;   
           
    // filedesc 0 = STDIN
   
mov       
$buffer,%ecx;           
    // @buffer
    mov     $(fdfile-buffer),%edx;        // strlen ( buffer )

    int       
$0x80;           
            // syscall


_writeinfile:           
           
    // write buf in file
   
mov        $4,%eax;   
           
    // syscall 4 = write
   
mov        fdfile,%ebx;   
            // get fdfile
in EBX
    mov       
$buffer,%ecx;           
    // @buffer
    mov     $(fdfile-buffer),%edx;        // strlen ( buffer )

    int       
$0x80;           
            // syscall


En effet, lorsqu'on écrit dans le fichier, on écrit une taille $(fdfile-buffer)
qui correspond à la taille du buffer. Quand on fait un 'cat
fichier.txt' on ne s'en rend pas compte car le caractère null termine
la chaine, mais la taille du fichier trahit cette anomalie de taille
d'écriture.


Pour résoudre cette anomalie, on peut utiliser le retour de "_readstdin:"
qui renvoie le nombre d'octets lus, et permettre une écriture dans le
fichier de la partie saisie au clavier uniquement. Le code de retour
étant dans EAX, il s'agira donc de copier EAX dans EDX avant d'écraser
EAX par le syscall 4 :

_writeinfile:   
           
            // write buf
in file

    mov    
%eax,%edx;           
// copy the character count of read(STDIN) in size of write(FILE)

    mov       
$4,%eax;             
// syscall 4 = write
    mov   
    fdfile,%ebx;   
     // get fdfile in EBX
    mov        $buffer,%ecx;      // @buffer
   
int        $0x80;   
           
    // syscall


Ainsi, on crée un fichier ayant la taille de ce qui a été pris sur STDIN et non la taille du buffer.


dune2.

Gentoo... que du bonheur ...
0
Rejoignez-nous