char
n'existe pas et char*=int*
).t[i][j]
) mais une l-value
en a au plus une (c'est soit t
soit t[i]
).
Rappel: en C une l-value est ce qu'on peut trouver sous un opérateur
d'assignation ou de pre/post-incrément/décrément.
Dans l'AST C-- du projet, l'assignation est explicitement restreinte
aux l-values x
et x[e]
(où x
est une variable et e
une expression).
Pour les incréments/décréments, l'AST n'est pas précis: vous pouvez
faire la même hypothèse dans votre code.
On m'a fait remarquer à juste titre que la restriction des l-values
est un peu artificielle. En fait, si l'on lit les règles de sémantique
opérationnelle du poly en ignorant (au moins) une remarque informelle,
elles expliquent comment traiter des l-values beaucoup plus générales,
par exemple (x+3*t[i++])[j]
ou simplement t[i][j]
.
Mais cela n'est pas demandé pour votre projet.
%rax
?
C'est la convention d'appel qui doit répondre à cette question, mais je
n'arrive pas à trouver de version convaincante qui garantisse quoi que
ce soit sur les bits de %rax
au delà de la taille de la
valeur retournée. Par conséquent on ne peut faire aucune hypothèse!
Si une fonction retourne un entier 32 bits, alors %eax
est correct mais on ne sait rien sur la moitié haute des bits de
%rax
.
Cela n'est pas si choquant dans la mesure où un vrai compilo connait
les types et va en général manipuler %eax
directement
s'il sait qu'un entier 32 bits a été retourné. Mais vous ne pouvez
pas faire ça dans votre compilo, où on ne "voit" que du 64 bit.
La solution proposée est de considérer que toutes les fonctions
déclarées dans votre fichier renvoient des entiers 64 bits,
et que toutes les autres renvoie du 32 bits, sauf quelques
exceptions comme malloc
.
En fonction de cette heuristique, vous pourrez alors étendre
%eax
sur 64 bits avec l'instruction movslq
.
(Merci à Aliaume Lopez.)
%rsp
sur 16 octets?Oui car cela fait partie de la convention d'appel x86-64 (voir spec, section 3.2.2, page 16)... même si ce point a été oublié dans le poly et la première version de l'aide-mémoire.
Il y a plusieurs moyens d'assurer l'alignement. N'hésitez pas à glaner des astuces sur le web ou à échanger entre vous sur ce point, comme sur les autres aspects très "cambouis" du projet.
Pas forcément, vous compilez du C-- et pas du C. La sémantique de C-- est définie en certains endroits où C laisse des comportements non définis. Voir par exemple ici.
(Merci à Laurent Prosperi.)
Oui! La convention n'est pas seulement là pour pouvoir appeler les fonctions de la librairie standard. Votre objectif est de faire comme dans un vrai compilateur, qui doit produire des fonctions qu'on puisse appeler selon la convention.
Comme d'habitude: utilisez un débogueur, relisez-vous, simplifiez ou reformuler votre test pour mettre le doigt sur le problème, allez dormir, etc.
En dehors de ces raisons habituelles, un problème assez vicieux s'est
manifesté plusieurs fois: si vos instructions assembleur ne sont pas
dans une section text
alors le débogueur ne "voit" plus
rien, les accès aux variables globales de la libc échouent, etc.
C'est vicieux car ce problème syntaxique évident n'est jamais signalé
en tant que tel comme une erreur par le compilateur.
Une technique s'applique directement: le printf, il n'y a pas de honte. Sinon, vous avez gdb.
N'oubliez pas qu'une instruction ne fait que 32 bits : il existe plusieurs modes d'adressage et si vous devez en utiliser 2 dans votre instruction (comme avec mov), certains couples ne sont pas possibles. Si vous dépassez ces 32 bits, vous aurez une erreur (comme par exemple, mov est utilisé trop souvent).
Aucune, ce sont des synonymes. La version avec un q est l'appelation Intel originale et l'équivalent sans q semble être introduit par GCC.
N'utilisez que jmp
, saut inconditionnel vu en cours.
Cette instruction prend en argument une adresse "absolue", en général
donnée par le biais d'un label.
Contrairement aux apparences jmpq
n'est pas un alias,
mais une variante du précédent permettant de sauter à une adresse
calculée dynamiquement.