Quel est le format de la x86_64 va_list structure?
Que quelqu'un a une référence pour la représentation de va_list
dans le x86_64 ABI (celui utilisé sur Linux)? Je suis en train de déboguer du code où la pile ou arguments semblent corrompus et il serait vraiment aider à comprendre ce que je suis censé voir...
- Pour le proche-monger: qu'en pensez-vous? Il n'est pas hors-sujet; c'est à propos de la programmation sur Linux!
Vous devez vous connecter pour publier un commentaire.
J'ai fait mon commentaire en réponse.
Cela peut aider. C'est une référence, quoique léger (MODIFIER: lien d'origine morts; il est remplacé Wayback Machine préservée lien).
La Liste d'arguments Variable de référence commence à la page 50, puis il va sur la page 52-53 documents
va_list
:Il s'avère que le problème était du ccg faire
va_list
de type tableau. Ma fonction était de la signature:et je voulais passer un pointeur vers
ap
à une autre fonction, j'ai donc fait:Malheureusement, les types de tableau de décomposition de type pointeur en fonction de listes d'arguments, donc, plutôt que de passer un pointeur vers la structure d'origine, j'ai été en passant un pointeur vers un pointeur.
Pour contourner le problème, j'ai changé le code pour:
C'est la seule solution portable que je pouvais venir, qui représente à la fois la possibilité que
va_list
est de type tableau et la possibilité qu'elle ne l'est pas.foo
prendre un argument de typeva_list *
?v*
fonctions de toujours prendre unva_list
argument, pas unva_list *
argument. C'est la norme de la convention et il serait ennuyeux pour les utilisateurs de la fonction à la violer.bar
utilise des informations supplémentaires pour déterminer le type de l'argument suivant et "pop" hors de la liste d'arguments. Si vous avez passéap
par valeur au lieu de en passant un pointeur, l'utilisation deap
aprèsbar
les retours, saufva_end
, seraient le résultat d'un comportement indéfini.va_copy
est pour.foo
, et chaque appel àbar
doit voir les effets de la précédente. C'est explicitement UB (selon ISO C) si vous passez par lava_list
; vous êtes tenus de passer un pointeur versva_list
pour cet usage.va_copy()
est utilisé avec un argument qui n'a pas de typeva_list
: siva_copy()
n'est pas une fonction (ce qui est explicitement autorisé), aucun réglage de paramètre vais être effectuée(!); cependant, on pourrait faire valoir que, comme la norme donne un prototype pourva_copy()
et de l'état que à à la mise en œuvre de la fonction, l'argument des ajustements sont implicitement supposé...va_list
parce queva_list
est de type tableau, et que cela rend l'utilisation deva_copy
pas défini? Ce paramètre "réglages" parlez-vous? Décomposition de la matrice de types de pointeurs n'a rien à voir avec leur passé à une fonction...va_copy
est de l'utiliser sur unva_list
vous avez obtenu comme argument. Si vous aviez obtenu avecva_start
, vous pouvez simplement appelerva_start
de nouveau pour obtenir une copie et il n'y aurait pas besoin deva_copy
.va_copy
changements. Vous obtenez toujours uneva_list
, alors pourquoi est-il tout d'un coup bien pour passer le pointeur de la copie? EDIT: j'ai eu l'idée de base maintenant... julio.meroh.net/2011/09/using-vacopy-to-safely-pass-ap.htmlva_list
vous avez reçu comme argument d'une autre fonction prenant unva_list
(tant que vous ne l'utilisez pas après que, à l'exception deva_end
). Il est également bon de passer un pointeur vers unva_list
....va_list ap;
vous donne un objet de typeva_list
de sorte que&ap
est de type pointeur versva_list
, la réception de l'argument, a déclaréva_list ap
n'est pas nécessairement signifieap
a typeva_list
. Siva_list
est de type tableau, le tableau de décomposition des règles pour les arguments de la fonction appliquer, puisap
est de type pointeur vers le pointeur-à-__typeof__(*ap)
, qui n'est ni de type compatible ni la juste valeur à transmettre à une fonction attend pointeur-à-va_list
(c'est un niveau supplémentaire d'indirection).va_copy
de temp est le seul moyen de résoudre ce problème.va_list
est ok, si le C99 nous dit que, ou pas (?). Au moins je me plais à assumerclang
ougcc
ont mis en œuvre C99 selon les spécifications complètes (?).sizeof
et attendent à ce que la taille de l'ensemble des données de l'objet, mais ce ne serait pas de travail, même si vous n'avez pas de passer un pointeur vers le type de tableau et de déréférencement (et juste après le tableau lui-même) (?)va_list
à une autre fonction, de sorte que la mise en œuvre de celle utilisée par rapport décalages à partir d'une base que seule la fonction d'appelva_start
pourrait savoir serait non-conforme.va_list ap
oùva_list
est défini par le type de tableau,ap
n'a pas de typeva_list
. Elle est de type__typeof__(*ap)*
. Tableaux ne sont pas des pointeurs. Donc&ap
n'a pas de typeva_list *
(pointeur de l'ensemble du tableau, dont la valeur est la même que pointeur vers le membre initial, mais dont le type est différente), dont elle aurait besoin d'avoir dans le but de les transmettre à une fonction attendva_list *
. Au lieu de cela&ap
a type__typeof__(*ap)**
, un pointeur de type pointeur dont la valeur n'a rien à voir avec l'adresse de lava_list
objet.foo
,ap
est converti entypeof(*ap) *
(selon C99) 2. Ensuite,bar
est appelée sur&ap
, qui est de typetypeof(*ap) **
3. En supposant que le reçu argument à l'intérieur debar
est nomméap_bar
: Siap_bar
est déréférencé, le résultat est un tableau réel, de sorte que le code machine fonctionnera différemment lors de l'utilisation de[]
ou*
que si c'était un__typeof__(*ap) **
(qui il est vraiment dans votre exemple).ap_bar *
est soumis à la même argument conversions (tableau en pointeur) comme indiqué au point 1; cette conversion peut alors produire des mauvais résultats lorsqu'il est appliqué à une variable de type__typeof__(*ap) *
.typedef int foo[1];
et les fonctions de la prise de ce type defoo
, ou un pointeur vers elle, comme un argument.Dans l'architecture i386, le va_list est un type de pointeur. Cependant, dans l'architecture AMD64, il est de type tableau. Quelle est la différence? En fait, si vous appliquez un & opération d'un type pointeur, vous obtiendrez l'adresse de ce pointeur variable. Mais pas n'importe comment beaucoup de fois vous demande & opération d'un type tableau, la valeur est la même, et est égale à l'adresse de ce tableau.
Alors, que devez-vous faire en AMD64? La façon la plus facile de passer de la variable de va_list dans une fonction, on est juste de passage, sans * ou & opérateur de.
Par exemple:
Il fonctionne, tout simplement! Et vous n'avez pas besoin de vous soucier de combien d'arguments que vous avez obtenu.