Exécution du code d'assemblage 32 bits sur un système Linux 64 bits & amp; Processeur 64 bits: Expliquer l'anomalie
Je suis dans un problème intéressant.J'oubliais, je suis sous 64 bits machine & OS et a écrit un 32 bits, le code d'assemblée. Je ne sais pas comment écrire 64 bits de code.
C'est le x86 32 bits assemblée code Assembleur Gnu (AT&T syntaxe) sur Linux.
//hello.S
#include <asm/unistd.h>
#include <syscall.h>
#define STDOUT 1
.data
hellostr:
.ascii "hello wolrd\n";
helloend:
.text
.globl _start
_start:
movl $(SYS_write) , %eax //ssize_t write(int fd, const void *buf, size_t count);
movl $(STDOUT) , %ebx
movl $hellostr , %ecx
movl $(helloend-hellostr) , %edx
int $0x80
movl $(SYS_exit), %eax //void _exit(int status);
xorl %ebx, %ebx
int $0x80
ret
Maintenant, Ce code doit s'exécuter correctement sur un processeur 32 bits & OS 32 bits à droite? Comme nous le savons processeurs 64 bits sont rétro-compatible avec les versions 32 bits des processeurs. Alors, qui également ne pas être un problème. Le problème se pose en raison de différences dans le système des appels & mécanisme d'appel dans les OS 64 bits & 32-bit OS. Je ne sais pas pourquoi, mais ils ont changé le système de numéros d'appel entre les versions 32 bits de linux & linux 64-bit.
asm/unistd_32.h définit:
#define __NR_write 4
#define __NR_exit 1
asm/unistd_64.h définit:
#define __NR_write 1
#define __NR_exit 60
De toute façon à l'aide de Macros à la place de numéro direct est payé. Sa s'assurer de la bonne système de numéros d'appel.
quand j'assemble & lien & exécuter le programme.
$cpp hello.S hello.s //pre-processor
$as hello.s -o hello.o //assemble
$ld hello.o //linker : converting relocatable to executable
Ses pas l'impression helloworld
.
Dans gdb son montrant:
- Programme terminé avec le code 01.
Je ne sais pas comment déboguer dans gdb. à l'aide de tutoriel, j'ai essayé de déboguer et d'exécuter l'instruction par instruction de la vérification des registres à chaque étape. c'est toujours en me montrant "le programme est sorti avec 01". Ce serait formidable si certains pouvaient me montrer comment déboguer ce.
(gdb) break _start
Note: breakpoint -10 also set at pc 0x4000b0.
Breakpoint 8 at 0x4000b0
(gdb) start
Function "main" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Temporary breakpoint 9 (main) pending.
Starting program: /home/claws/helloworld
Program exited with code 01.
(gdb) info breakpoints
Num Type Disp Enb Address What
8 breakpoint keep y 0x00000000004000b0 <_start>
9 breakpoint del y <PENDING> main
J'ai essayé de courir strace
. C'est sa sortie:
execve("./helloworld", ["./helloworld"], [/* 39 vars */]) = 0
write(0, NULL, 12 <unfinished ... exit status 1>
- Expliquer les paramètres de
write(0, NULL, 12)
appel système dans la sortie de strace? - Ce exactement qui se passe? Je veux savoir la raison pour laquelle exactement sa sortie avec exitstatus=1?
- Certains une, merci de me montrer comment déboguer ce programme à l'aide de gdb?
- Pourquoi ont-ils changer le système de numéros d'appel?
- De bien vouloir modifier ce programme de manière appropriée afin qu'il puisse s'exécuter correctement sur cette machine.
EDIT:
Après la lecture de Paul R réponse. J'ai vérifié mes fichiers
claws@claws-desktop:~$ file ./hello.o
./hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
claws@claws-desktop:~$ file ./hello
./hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
Je suis d'accord avec lui que ceux-ci devraient être ELF 32-bit mobile & fichier exécutable. Mais cela ne veut pas répondre à mes à mes questions. Toutes mes questions, encore des questions. Ce qui se passe exactement dans ce cas? Quelqu'un peut s'il vous plaît répondre à mes questions et de fournir un x86-64 version de ce code?
source d'informationauteur claws
Vous devez vous connecter pour publier un commentaire.
N'oubliez pas que tout par défaut sur un système d'exploitation 64 bits a tendance à présumer de 64 bits. Vous devez vous assurer que vous êtes (a) en utilisant les versions 32 bits de votre #inclut le cas échéant (b) la liaison avec 32 bits des bibliothèques et (c) la construction d'un exécutable 32 bits. Il serait probablement aider si vous avez montré le contenu de votre makefile si vous en avez un, sinon les commandes que vous utilisez pour construire cet exemple.
FWIW j'ai changé votre code légèrement (_start -> main):
et l'a construit comme ceci:
verfied que nous avons un exécutable 32 bits:
et il semble OK:
Comme l'a noté Paul, si vous voulez construire les binaires 32 bits sur un système 64 bits, vous devez utiliser l'-m32 drapeau, qui peut ne pas être disponible par défaut sur votre installation (64 bits des distributions Linux de ne pas inclure de 32 bits compilateur/linker/lib support par défaut).
D'autre part, vous pourriez construire votre code 64 bits, dans ce cas, vous devez utiliser la version 64 bits de conventions d'appel. Dans ce cas, le système de numéro d'appel va en %rax, et les arguments vont en %de l'aqr, %rsi, %rdx
Modifier
Meilleur endroit que j'ai trouvé pour ce qui est http://www.x86-64.orgspécifiquement abi.pdf
Cpu 64 bits peut exécuter du code 32 bits, mais ils ont à utiliser un mode spécial pour le faire. Ces instructions sont valides en mode 64 bits, donc rien ne vous a empêché de construire une 64-bit exécutable.
Votre code construit et fonctionne correctement avec
gcc -m32 -nostdlib hello.S
. C'est parce que-m32
définit__i386
donc/usr/include/asm/unistd.h
comprend<asm/unistd_32.h>
qui a le droit constantes pour lesint $0x80
ABI.Voir aussi L'assemblage des binaires 32 bits sur un système 64 bits (GNU toolchain) pour en savoir plus sur
_start
vsmain
avec/sans libc et statique vs dynamique des fichiers exécutables.Techniquement, si vous aviez utilisé le droit d'appeler les numéros de votre code d'arriver à travailler de mode 64 bits ainsi: Qu'advient-il si vous utilisez la version 32 bits de type int 0x80 ABI Linux en 64 bits de code? Mais
int 0x80
n'est pas recommandé dans le code 64 bits. (En fait, il n'est jamais recommandé. Pour plus d'efficacité, code 32 bits devrait appeler à travers le noyau est exporté VDSO page afin qu'il puisse utilisersysenter
rapide des appels système sur des Processeurs qui le prennent en charge).Bonne question.
Sur Linux,
int $0x80
aveceax=1
estsys_exit(ebx)
quel que soit le mode le processus appelant a été en. Les 32 bits de l'ABI est disponible en mode 64 bits (à moins que votre noyau a été compilé sans i386 support de l'ABI), mais ne l'utilisez pas. Votre statut de sortie est demovl $(STDOUT), %ebx
.(BTW, il y a un
STDOUT_FILENO
macro définie dansunistd.h
mais vous ne pouvez pas#include <unistd.h>
à partir d'un.S
car il contient également C prototypes qui ne sont pas valides asm syntaxe.)Avis que
__NR_exit
deunistd_32.h
et__NR_write
deunistd_64.h
sont à la fois1
de sorte que votre premièreint $0x80
sort de votre processus. Vous utilisez le mauvais système de numéros d'appel pour l'ABI vous êtes en invoquant.strace
est en train de décoder de manière incorrectecomme si vous aviez invoquésyscall
(parce que c'est l'ABI un processus 64 bits est prévu de l'utiliser). Quelles sont les conventions d'appel pour UNIX & appels système Linux sur x86-64eax=1
/syscall
signifiewrite(rd=edi, buf=rsi, len=rdx)
et c'est de cette façonstrace
est mal décodage votreint $0x80
.rdi
etrsi
sont0
(akaNULL
) à l'entrée de_start
et votre code définitrdx=12
avecmovl $(helloend-hellostr) , %edx
.Linux initialise les registres à zéro dans un nouveau processus après execve. (L'ABI dit pas défini, Linux choisit zéro pour éviter info fuites). Dans votre statiquement lié exécutable,
_start
est le premier utilisateur de l'espace de code qui s'exécute. (Dans une dynamique exécutable, l'éditeur de liens dynamique s'exécute avant_start
et de ne laisser de déchets dans des registres).Voir aussi le x86 la balise wiki pour plus d'asm liens.