1. C'est génant si on passe une partie des arguments par registres, une autre par la pile (obligé, avec une va_list) ? Il suffit de ne préciser des registres que là où on en utilise et ça va ? 2. C'est gênant si on utilise des registres >= a2 ? "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
C'est génant si on passe une partie des arguments par registres, une autre par la pile Là aussi, ExtGraph utilise de nombreuses telles fonctions (même s'il n'y a aucune va_list): regarde les headers 2. C'est gênant si on utilise des registres >= a2 ? Mieux vaut ne pas en abuser car dans les programmes client compliqués, les registres d'adresse a2-a6 (moins ceux qui sont utilisés par le frame pointer / la global register variable) sont les meilleurs moyens de stocker des variables pointeurs à longue vie. Ceci dit, plusieurs fonctions d'ExtGraph et TIGCCLIB, plutôt parmi les moins courantes, utilisent des registres >= a2. Membre de la TI-Chess Team. Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP. |
short TestCollide8_R(short x0 asm("%d0"), short y0 asm("%d1"), short x1 asm("%d2"), short y1 asm("%d3"), unsigned short height,
const unsigned char* data0 asm("%a0"), const unsigned char* data1 asm("%a1")) __attribute__((__stkparm__)); Bon, si je comprends bien, ici c'est la totale ? - Passage d'arguments par registre (tiens au fait, faut mettre les '%' ??) - Utilisation de d3 - Passage d'arguments par la pile Le stkparm sert à quoi ? Ce n'est pas évident que les arguments sans 'asm("...")' sont passés par la pile ? Ou alors il est obligatoire parce qu'on a aussi des passages par registre ? Et est-ce que ça veut dire qu'un programme utilisant d3 comme variable globale déconnerait en utilisant une telle fonction ? "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
(tiens au fait, faut mettre les '%' ??) Non, ça n'est pas obligatoire Le stkparm sert à quoi ? L'idée est de forcer le compilo à passer height sur la pile: Ce n'est pas évident que les arguments sans 'asm("...")' sont passés par la pile ? Pas forcément, si l'utilisateur utilise un réglage du genre "-mregparm=9" (déconseillé par la doc). De mémoire (ça fait fort longtemps que le code est comme ça et qu'il fonctionne Et est-ce que ça veut dire qu'un programme utilisant d3 comme variable globale déconnerait en utilisant une telle fonction ? Si ni le compilo (sauvegarde/restauration automatique) ni toi (sauvegarde/restauration explicite si le compilo ne le fait pas) ne font attention, ça devrait merder, oui. Membre de la TI-Chess Team. Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP. |
Ok, merci beaucoup pour tout. J'ai déjà réécrit ma fonction en utilisant ces features (mais sans utiliser a2+/d3+). J'ai un proto de ce genre maintenant : ; int pdtlib__ManageCmdline (CMDLINE* CmdLine, void* Data, const char* OptList, int (*Callback)(void* Data asm("a0"), int Status asm("d0")),
; void (*SwitchFunc)(void* Data asm ("a0"), char Sign asm ("d0")), ...); C'est fou ce que je gagne en asm. J'ai réécrit (je sais, pas bien Rectif hic à tiffes : 399 "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Folco (./149) : Oui, mais tu devrais aussi mettre __attribute__((stkparm)) pour que ça marche aussi quand le programme qui utilisera la lib est compilé avec -mregparm. 2. C'est gênant si on utilise des registres >= a2 ? Non, sauf %a6 (%fp) et %a7 (%sp). (J'éviterais aussi %a5 (OPTIMIZE_ROM_CALLS), mais pour une lib kernel, ce n'est pas si important que ça.) Folco (./151) : Oui. (Et non, Lionel, GCC ne gère pas ça.) C'est une des raisons pour lesquelles les global register variables sont une mauvaise idée. |
les global register variables sont une mauvaise idée. Ne sois pas si général dans tes affirmations Tu sais bien qu'en ASM, Martial utilise souvent, pour plusieurs raisons qui vont dans le même sens (plus grande efficacité du code + absence de relocations), une global register variable pointeur vers les données internes du programme. Pattern shared memory: priorité à l'efficacité, au détriment du couplage, de la cohésion et de la maintenabilité. [EDIT: dernière phrase: ajout du couplage] Membre de la TI-Chess Team. Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP. |
Merci bien pour tout. "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Il y a un moyen de dire à GCC qu'une fonction ne détruit que, par exemple, a0, afin de favoriser l'optimisation ? "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Ca ne me dit rien, en tout cas rien de direct (peut-être avec de l'ASM inline). Ceci dit, comme tu le sais, ce genre de micro-optimisations, même en ASM pur, est une pente fort glissante Membre de la TI-Chess Team. Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP. |
Ben tant qu'à être au fond du trou tu sais Mais ok, merci "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Peut-on créer une table d'offsets en C ? De type de celles qu'on utilise pour avoir une table de sauts pc-relatifs en assembleur. Ca serait du genre : const short OffsetsTable [] = {Func1-&OffsetTable, Func2-&OffsetTable, ...};
void Func1() {}
void Func2() {}
int main ()
{ LibCall(OffsetTable);} C'est faisable et fiable ? "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Déjà, est-ce que ça compile, ça ? « Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau |
Tu poses la même question que Lionel "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Ça ne compile même pas. |
Kevin, c'était du C-like bien évidemment. En vrai C-kikompile: #include "kernel.h"
#define USE_TI89
void func1 (void)
{
}
void func2 (void)
{
}
int pwet (unsigned short* Table)
{
return Table[0] = Table[1];
}
int _main (void)
{
unsigned short Table [] =
{
(unsigned short)((long)func2 - (long)Table),
(unsigned short)((long)func1 - (long)Table),
};
return pwet(Table);
} Compilation : tigcc -Wall -W --save-temps --optimize-code --optimize-relocs --cut-ranges -v pwet.c -o pwet Asm produit : func1:
link.w %fp,#0
unlk %fp
rts
.even
.globl func2
func2:
link.w %fp,#0
unlk %fp
rts
.even
.globl pwet
pwet:
link.w %fp,#0
move.l 8(%fp),%a0
addq.l #2,%a0
move.w (%a0),%d0
move.l 8(%fp),%a0
move.w %d0,(%a0)
move.l 8(%fp),%a0
move.w (%a0),%d0
unlk %fp
rts
.even
.globl _main
_main:
link.w %fp,#-4
move.l #func2,%d0
move.w %d0,%d1
move.l %fp,%d0
subq.l #4,%d0
move.w %d0,%d0
move.w %d1,%a0
sub.w %d0,%a0
move.w %a0,%d0
move.w %d0,-4(%fp)
move.l #func1,%d0
move.w %d0,%d1
move.l %fp,%d0
subq.l #4,%d0
move.w %d0,%d0
move.w %d1,%a0
sub.w %d0,%a0
move.w %a0,%d0
move.w %d0,-2(%fp)
move.l %fp,%d0
subq.l #4,%d0
move.l %d0,-(%sp)
jbsr pwet
addq.l #4,%sp
unlk %fp
rts J'ai pas regardé ce qu'il merdouille, mais il est déjà évident qu'il reloge les adresses des fonctions, qu'il ne crée pas de table de donnée etc... Sauf s'il y a un moyen de lui faire comprendre exactement ce que je veux, je suis cuit. On aura au passage noté les optimisations spectaculaires effectuées sur les fonction vides, les link an,#0 magistraux etc... "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Tu as oublié de spécifier le -O c'est sans doute pour ça. (Il faut mettre -O2 ou -Os suivant que tu veux optimiser en vitesse ou en taille, sinon il n'optimise pas du tout. Enfin il me semble.) Forum Cultures du monde — forum littéraire Membrane fondatrice de la confrérie des artistes flous. L'univers est-il un dodécaèdre de Poincaré ? (``·\ powaaaaaaaaa ! #love# |
J'ai essayé de déclarer el tableau en volatile, en me disant que si "autre chose" pouvait accéder à ce tableau, le compilateur serait bien obligé de lui donner la forme attendue (un véritable tableau de unsigned short). Mais j'ai cette erreur : pwet.c:20: error: initializer element is not constant (near initialization for 'Table[0]') pwet.c:21: error: initializer element is not constant (near initialization for 'Table[1]') Il me dit ça pour les deux lignes du tableau... (comme si je déclare le tableau static d'ailleurs). cross -> oups merci ^^ => même taille de binaire et à vue de nez même code "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
volatile ? Edité par Sally le 15-10-2010 à 15:12:34.Je ne comprends pas ce qu'il ne fait pas bien dans le code assembleur que tu as mis, ça me semble correct. Il crée un tableau de deux cases sur la pile (link.w %fp,#-4) et il y met ce que tu lui as dit autant que je puisse en juger (enfin il convertit les adresses en short avant de faire la soustraction et non après, mais ça change rien il me semble, tu ne peux pas avoir de retenue de la partie de poids fort vers celle de poids faible) sinon si tu veux éviter les link il me semble qu'il faut mettre -fomit_frame_pointer Forum Cultures du monde — forum littéraire Membrane fondatrice de la confrérie des artistes flous. L'univers est-il un dodécaèdre de Poincaré ? (``·\ powaaaaaaaaa ! #love# |
static peut-etre plutot non ? |
Ah oui tu voudrais que le tableau ne soit pas sur la pile ? dans ce cas il faut effectivement le déclarer soit static soit comme une variable globale (dans les deux cas il sera créé à la compilation et non au runtime), par contre dans ce cas il essaye de calculer la valeur de l'initialiseur au moment de la compilation, et en l'occurrence il ne peut pas puisqu'il ne connaît pas les adresses, c'est pour ça qu'il n'est pas content. Il suffit que tu sépares la déclaration et l'initialisation, ainsi dans le fichier le tableau ne sera pas initialisé et ensuite il le sera au runtime. Edit : mais si ton but était qu'il précalcule le contenu du tableau, je ne pense pas que ce soit possible, parce qu'il ne peut pas connaître l'offset avant d'avoir compilé. Il faudrait une étape de bootstrap pour pouvoir faire ça ^^ Forum Cultures du monde — forum littéraire Membrane fondatrice de la confrérie des artistes flous. L'univers est-il un dodécaèdre de Poincaré ? (``·\ powaaaaaaaaa ! #love# |
Bah, j'aurais dû expliciter mon ./163: on avait déjà cette discussion! Une différence d'adresses n'est pas une constante en C (sauf dans le cas particulier où ce sont 2 champs de la même structure), donc 1. tu ne peux pas l'utiliser dans une variable globale ou statique et 2. dans une variable locale, c'est calculé à coup de relogements. Le compilateur C ne sait pas où se situent les fonctions et beaucoup de formats objet ne prévoient pas de relogement différence d'adresses. Ce serait théoriquement implémentable dans TIGCC en fonction des paires de relogements positif/négatif gérées par ld-tigcc, mais pour ça il faudrait modifier GCC et je ne peux pas dire a priori l'ampleur des modifications nécessaires. |
Godzil (./168) : C'est ce que j'ai commencé par essayer, sans succès. Sally (./169) : J'ai essayé aussi. Kevin Kofler (./170) : Je m'en souviens bien, je n'avais tout simplement pas fait le lien entre les deux. Merci de l'explication. Bon ben tant pis, je laisse tomber cette idée, merci pour tout. "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Bon, je ressors ce topic un peu au hasard, il fera l'affaire. Il y a un truc que je ne comprends pas du tout avec l'arithmétique des pointeurs void : Soit ce code : void* ArcPtr; void* ArcBasePtr; long Offset; // initialisations toussa ArcPtr = ArcBasePtr + Offset; Ben... Ca marche J'arrive à additionner un long à un void* sans qu'il ne trouve rien à redire. Il est magicien ? Si je regarde mon bouquin, il y est explicitement dit que : Le type void* ne peut pas être soumis à des calculs arithmétiques Je ne comprends donc pas : - ça compile - ça semblerait malgré tout interdit (et ça semble logique... encore que... niveau assembleur c'est bateau comme opération) Je ne sais pas par contre ce que ça génère, et surtout si c'est safe, quelles sont les règle en la matière ! Merci de vos éclaircissations. "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Je crois que des paramètres de compilation peuvent être utilisés pour autoriser ou interdire l'arithmétique sur les pointeurs void. Pour ce que ça fait, je suppose que ça incrémente comme s'il s'agissait d'un char*, mais c'est à vérifier. Tu compiles en -Wall ? La fin d'un monde souillé est venue. L'oiseau blanc plane dans le ciel annonçant le début d'une longue ère de purification. Détachons-nous à jamais de notre vie dans ce monde de souffrance. Ô toi l'oiseau blanc, l'être vêtu de bleu, guide nous vers ce monde de pureté. - Sutra originel dork. |
Ca, c'est une extension de GCC au standard C. Ton livre documente le C standard - et donc, pas cette extension non standard Il y a des gens qui adorent l'arithmétique sur les pointeurs void. Il y en a qui ne voient pas trop l'intérêt par rapport à l'utilisation de char * / unsigned char * / int8_t * / uint8_t * ou types équivalents (pointeur vers octet). Il y en a qui trouvent foutrement stupide cette extension non portable et le fait que sizeof(void) == 1. A toi de voir Membre de la TI-Chess Team. Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP. |
Ximoon (./173) : -Wall -W J'ai renoncé à -pedantic devant la volée de warnings déclenchés par (gcc4)ti(gcc)lib Lionel Debroux (./174) : Ah ok merci. Plus qu'à trouver la doc de cette extension pour savoir précisément ce qu'elle fait (void* -> char* implicite j'imagine). Ximoon (./173) : Oué voilà, à vérifier. En tout cas, ça serait con qu'il en soit autrement, transcrit littéralement en assembleur c'est ce que ça donne... Lionel Debroux (./174) : Quand tu parcours un fichier AMS de type aléatoire, je ne vois pas en vertu de quoi je dirais que mon pointeurs est plus un char* qu'un short* ou qu'un mékooyes*. Même si char* parait plus propre, ça reste de toute façon un hack, et ça nécessitera aussi des casts dans tous les sens. Merci encore de vos réponses. "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Oh, key : http://tigcc.ticalc.org/doc/gnuexts.html#SEC79 http://gcc.gnu.org/onlinedocs/gcc-2.95.3/gcc_4.html#SEC78 Sanqse euguèine. C'est pas mal pour s'affranchir de pas mal de casts casse-bonbons : FileInfo->Tag = *(char*)(ArcPtr + *(short*) ArcPtr + 1); "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Hmm, ya quand même un truc que j'ai du mal à visualiser : *(unsigned short*)(ArcPtr + 1) Avec ArcPtr qui est un void*. Alors, comment ça se passe ? 1ère idée : On fait l'addition dans la parenthèse, donc en asm je vais avoir un addq.l #1,a0. Puis on cast en (unsigned short*). Ca pue l'address error à des kilomètres. 2ème idée : On caste le contenu de la parenthèse en (unsigned short*). Puis on résoud l'addition, donc en asm on fait un addq.l #2,a0. J'arrive pas à savoir comment le compilateur va conidérer les choses. Que choisit-il comme solution ? "MSVC, le soft qui arrive à générer des problèmes à partir de solutions" © |
Les deux. Enfin plus sérieusement comme tu l'as dit pour la solution deux « On caste le contenu de la parenthèse en (unsigned short*) »… Conclusion la solution 1 est la bonne, mais la 2 aussi sauf que tu ne l'a pas interprétée correctement (ça donne aussi addq.l #1,a0… Ta deuxième phrase est une contradiction avec la première selon les principes du langage C La règle à appliquer, comme à peu près pour tout en C, c'est la priorité des opérateurs, dont découle l'ordre d'évaluation des expressions. Deux choses ici: On applique le cast sur le contenu de la parenthèse. Les parenthèses ont priorité absolue. (Comme en maths… Bien sur le groupe le plus imbriqué est le plus prioritaire, mais il n'y a pas d'imbrication ici) Par conséquent, le contenu de la parenthèse est évalué en premier puis ensuite on lui applique le cast, qui est un opérateur unaire de priorité inférieure. C'est à dire la solution 1 C'est assez simple, et il n'y a jamais d'exception (enfin je suis pas sur que que cas des pointeurs de fonctions rentre parfaitement là dedans, mais admettons que si parce que j'ai la flemme de vérifier). PS: en gras la version simple T'as un problème ? Tu veux un bonbon ? [CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes |
Pour faire de l'arithmétique de pointeurs, l'utilisation de char * au lieu de void * peut en effet nécessiter davantage de casts. Cependant, c'est comme ça qu'on fait en C standard. Ici, tu ne te soucies pas de portabilité entre les principaux compilos existants, mais dans le cas général, cette extension non standard casse la compatibilité avec certains des principaux compilos. Membre de la TI-Chess Team. Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP. |