[NASM / Linux 64] Utiliser les fonctions standard du C
Bonjour,
Je suis débutant en programmation assembleur, j'utilise NASM sous Ubuntu 64 pour créer des programmes 64 bits et il m'est impossible d'utiliser les fonctions standard du C (printf en l'occurence)...Voici mon code :
Code:
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
| section .data
s_err: db 'Use: ./echo <string>', 0xA
s_err_len: equ $ - s_err
hello: db 'Hello world!', 0xA
helloLen: equ $ - hello
s_test: db 'Hello !', 0xA, 0x0
section .text
global _start
extern printf
_start:
; Checking argc
pop rax
cmp rax, 2
je args_ok
args_nok:
; Displaying error message (sys_write)
mov rax, 4
mov rbx, 2
mov rcx, s_err
mov rdx, s_err_len
int 80h
; Exiting (1)
mov rax, 1
mov rbx, 1
int 80h
args_ok:
; TODO
push s_test
call printf
pop rax
; Exiting program (0)
mov rax, 1
mov rbx, 0
int 80h |
Je créé l'exécutable de cette façon :
Code:
1 2
| nasm -f elf64 echo.asm
ld -s -m elf_x86_64 -o echo echo.o -lc |
A l'exécution :
Code:
1 2
| ./echo
bash: ./echo: Aucun fichier ou dossier de ce type |
Quel est le problème ? Si je vire l'appel à printf dans le code assembleur et le lien avec la bibliothèque C, ça fonctionne...
Edit : je précise que le fichier echo existe bien dans le répertoire et qu'il est exécutable !
Merci de votre aide !
j'ai fait un test qui fonctionne...
Bonjour,
Je me permet de vous répondre car je cherchais aussi une solution.
Je me suis permis de regarder le document envoyé par dapounet. Ce document est vraiment bien et ce type d'information m'intéresse car je suis en train de découvrir l'assembleur en 64bits.
De mon côté j'ai simplifié l'appel à la fonction 'puts'.
J'ai d'abord fait un premier code ou je transmettais le paramètre de la fonction par la pile, comme en 32bits... ça compile, ça link, mais ça marche pas : bash: ./echo: Aucun fichier ou dossier de ce type:?
Alors j'ai testé avec le registre rcx... ça marche toujours pas, mais c'est mieux : segmentation fault :evilred:
Puis, d'après la doc, ce serait 'rdi' le premier registre à utiliser... et ça marche ! :king:
voici mon petit programme de test (hello.asm) :oops:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
section .data
hello: db 'Hello world!',0 ; 'Hello world!' terminé par le fameux \0 pour le C
section .text
extern puts ; déclaration de la fonction puts
global _start
_start:
mov rdi, hello ; store the parameter in
xor eax, eax ; je ne sais pas si cela sert ?
call puts ; appel de la fonction puts !
mov eax,1 ; system call pour exit (sys_exit)
mov ebx,0 ; Exit avec return code of 0 (no error)
int 80h |
pour compiler le tout :
Code:
nasm -f elf64 hello.asm
puis l'édition des liens :
Code:
ld --dynamic-linker /lib/ld-linux-x86-64.so.2 -lc -o hello hello.o
Voilà, je n'ai pas encore tout compris, mais c'est un début...
l'ordre des paramètres est :
rdi, rsi, rdx, rcx, r8, r9, xmm0-7
donc si vous transmettez la valeur à afficher et le format avant le call à printf sur rdi,rsi (il faudra peut-être inverser l'ordre des paramètres car je n'ai pas compris tout dans le document).
merci de me dire comment vous avez fait si vous y arrivez.
majµcarma
ça va finir par marcher !
Je pense qu'il s'agit d'une vieille habitude...
Avant, un "mov ax, 0" nécessitait plus de cycle processeur qu'un xor ax,ax. Ce qui aujourd'hui, d'après les doc des constructeurs n'est plus vraiment exact.
Là où l'on gagne un peu, c'est sur la taille finale du programme (mais j'en suis pas certain à 100% pour le mode 64bits). En tout cas, autrefois :mouarf: lorsque nous programmions encore en 32bits, un mov eax,<valeur_entière> pouvait prendre de 1 à 4 octets en mémoire selon la la taille dudit nombre à copier. alors qu'un xor ax, ax représente un simple octet dans 100% des cas...
Ici dans notre exemple, il va de soit que cela ne change pas grand chose...
D'ailleur, je pense que nous ne sommes pas sortis de l'auberge. En fait, quand on passe une valeur entière, ça marche plus ! A priori, la difficuté ne provient pas de l'assembleur, mais plutot du C. En effet, printf peut avoir un nombre d'arguments variables. Je bouquine la doc du constructeur mais je n'ai rien trouvé à ce sujet.
Au fait, la doc est disponible en ligne : (5 volumes de 400 pages en moyenne...)
http://developer.amd.com/documentati...s/default.aspx
Je n'ai pas vraiment pu me pencher sur le problème, mais cela vaut la peine de chercher. Je le fait de temps en temps donc ça va pas vite :koi:.
En tout cas, si tu débutes en assembleur, je te conseille de commencer par t'habituer avec des compilateurs comme MASM ou TASM en mode 16bits :bug: :cry:sous DosBox. Il y a beaucoup plus de docs sur le sujet. C'est relativement simple comparé au monstre que nous essayons de dompter... Ensuite, les techniques acquises te serviront pour les modes 32 ou 64bits Linux ou Windows.
Voilà.
majµcarma