60

int pdtlib__ManageArgs (CMDLINE* CmdLine, int (*Callback)(int Status), void (*SwitchFunc)(char Sign), const char* OptList, ...)

?

61

Ouep, mais le but, comme expliqué ici ( blogs/blog.php?id=400 ) est d'avoir une adresse de fonction par élément de OptList (liste de string).
Or dans ton proto, il y a plein de liste de strings (alors qu'une suffit), et une seule fonction à appeler.

62

non mais j'ai pris ton propre code de ./33 et j'ai permuté 2 arguments pour éviter que le dernier soit un pointeur de fonction, hein grin

63

Il me semblait bien que ça n'allait pas plus loin grin
Mais... j'ai vu cette limitation pour les fonctions à va_start, mais pas à va_arg. Peut-être que ça pourrait marcher ? Déclarer va_start pour un simple long, ou même un void*, puis lire des pointeurs castés en pointeurs de fonction cheeky

A essayer ^^

64

Bon, Godzil a apparemment trouvé une solution qui compile à base de typedef. A vérifier, mais déjà un grand merci à lui pour y avoir pensé (et merci aussi à tous les autres hein grin). smile

65

Et effectivement, ça compile et ça semble marcher \o/

66

67

Autre question, sans grande importance cette fois.

J'ai ce code C :
typedef struct CMDLINE
{
	int argc;
	const char** argv;
	int argit;
} CMDLINE;


const char* pdtlib__GetCurrentArgPtr (CMDLINE* CmdLine)
{
	return CmdLine->argv[CmdLine->argit];
}

qui donne ce code assembleur :
pdtlib__0002:
	move.l 4(%sp),%a0
	move.w 6(%a0),%d0
	ext.l %d0
	move.l 2(%a0),%a0
	lsl.l #2,%d0
	move.l (%a0,%d0.l),%a0
	rts

Personnellement, j'aurais écrit :
pdtlib__0002:
	move.l 4(%sp),%a0
	move.w 6(%a0),%d0
-	ext.l %d0                  | inutile, un word suffit, et d0 représente un int de toute façon, deux octets sur TI...
	move.l 2(%a0),%a0

-	lsl.l #2,%d0
+	add.w %d0,%d0          | plus rapide
+	add.w %d0,%d0

-	move.l (%a0,%d0.l),%a0
+	move.l (%a0,%d0.w),%a0

	rts

Comment lui dire de faire mieux ?

68

j'imagine que tu t'attends à quelque chose de plus efficace que

printf("fais mieux\n");

désolé, jarfrépus!

69

Alors déjà le compilateur ne peut pas utiliser du %d0.w parce que l'indice maximum est 32767 et 4*32767 (ou même 4*(65518/4), ce qui ne déborde pas d'un handle!) ne tient pas dans un int.

Et ensuite, pour le lsl vs. 2*add, je rappelle que TIGCC utilise -Os par défaut (du moins avec les EDIs – en ligne de commande c'est -O0, il faut explicitement activer l'optimisation), et qu'en -Os, on s'en fout si c'est plus rapide. Le lsl prend 2 fois moins de place, le nombre de décalages (shift count) étant codé dans l'instruction. De plus, si je me rappelle bien, les vitesses ne se comportent pas de la même manière en .l (qu'on est obligés d'utiliser ici, cf. le premier paragraphe) qu'en .w.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

70

Merci bien.

Et ya aucun moyen de rendre ça intelligent ? Comment pourrait-on passer plus de 32767 arguments à la ligne de commande de PedroM (parce que c'est de ça qu'il s'agit ici) ? Aucun moyen de le forcer à ça ? (et je compile en -02)

71

A tout hasard, au lieu de
CmdLine->argv[CmdLine->argit];
essaie la macro DEREFSMALL (peu lisible, je sais grin) qui est notamment dans ExtGraph:
#ifndef __HAVE_DEREFSMALL
#define __HAVE_DEREFSMALL
//! Dereferences a pointer: DEREFSMALL(\a p,\a i) does the same as <code>p[i]</code>, but in a faster and smaller way.
// Doing the same thing using inline assembly saved ~100 bytes on an internal, buggy version of tthdex.
// Credits go to Kevin Kofler for its generic definition and the &* trick.
// 2.00 Beta 5: added ifndef/define pair so as to minimize incompatibility chances with the (same)
// definition that could be added to TIGCC some day.
#define DEREFSMALL(__p, __i) (*((typeof(&*(__p)))((unsigned char*)(__p)+(long)(short)((short)(__i)*sizeof(*(__p))))))
#endif


[EDIT: ajout de la partie non-Doxygen du commentaire.]
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

72

outch, fallait oser penser à écrire &*(a) grin

73

Merci beaucoup. Mais je ne comprends pas ce code, et je n'utilise jamais du code que je ne comprends pas. Au mieux, je vais réfléchir à ça. Puis j'aima pas les macros. embarrassed

Mais merci beaucoup quand même, je vais en apprendre grin

74

(long)(short)((short)(i)*sizeof(*(p))) calcule le nombre d'octets qu'il faut pour arriver au i-ième élément d'un tableau de choses de type *p.
Ensuite, tu ajoutes ça à un pointeur vers un unsigned char, pour obtenir l'adresse absolue du i-ème élément du tableau de choses de type *p commençant à l'adresse p, sous forme de pointeur vers un unsigned char.
Et le truc bizarre devant ce que je viens de décrire, est juste une façon de convertir ce pointeur vers un unsigned char en un pointeur vers un type p (avec la petite finesse &*, nécessaire pour que la macro puisse traiter certains types de tableaux), puis de le déréférencer.
p[ i ], c'est à dire, *(p+i), c'est bien ce que tu voulais faire, non ? grin


Vu qu'en C, il n'y a pas de paramètres génériques (templates) pour les fonctions, je vois mal comment se passer d'une macro embarrassed
Si tu passes un jour à un langage où il n'y a pas de préprocesseur, tu verras que tu regretteras ce bon vieux préprocesseur grin
avatar
Membre de la TI-Chess Team.
Co-mainteneur de GCC4TI (documentation en ligne de GCC4TI), TIEmu et TILP.
Co-admin de TI-Planet.

75

Oui, certes, je crois que je vais devoir m'y faire grin

Bon, je reviens à ma question initiale :


Et euh... y a-t-il un moyen pour copier du code dans la pile ? En fait, en asm, je rassemble les pointeurs de libcall/syscall dont j'ai besoin dans la pile, et je les fait précéder à tout hasard de $4EF9 embarrassed

Ca ressemble à ça :
pile améliorée
\RegTable:						; WARNING: will fail using functions > lib@00FF (should use word sized offsets)
	moveq.l	#0,d0
\RegLoop:
	move.b	(a1)+,d0
	bne.s	\Continue
		tst.b	(a1)
		bne.s	\Continue			; End of table: dc.b 0,0
			rts
\Continue:
	pea	(a4)
	RAMC	RAM_kernel::LibsPtr
	addq.l	#4,sp
	moveq.l	#0,d0					; PreOS bug: LibsPtr destroys d0
	move.b	(a2)+,d0
	move.w	#$4EF9,0(a6,d0.w)
	move.l	a0,2(a6,d0.w)
	bra.s	\RegLoop

avec les offsets qui vont bien pour obtenir les numéros des libcall/syscall et l'offset de leur pointeur dans la pile :
superbes tables
ButillibCallsTable:
    dc.b    BUTILLIB_InitCmdLine
    dc.b    BUTILLIB_GetCurrentArgPtr
    dc.b    BUTILLIB_GetNextArgPtr
    dc.b    BUTILLIB_IsArgSwitch
    dc.b    BUTILLIB_IsNextArg
    dc.b    BUTILLIB_GetFilePtr
    dc.b    BUTILLIB_CheckFileType
    dc.b    BUTILLIB_ExecSwitchRoutine
    dc.b    BUTILLIB_SkipDummyLines
    dc.b    BUTILLIB_SkipSpaces
    dc.b    BUTILLIB_SkipLine
    dc.b    BUTILLIB_GetFileHandle
    dc.b    BUTILLIB_GetPrevArgPtr
    dc.b    BUTILLIB_AdvanceToChar
    dc.b    0,0
ButillibCallsOffsets:
    dc.b    INIT_CMDLINE
    dc.b    GET_CURRENT_ARG_PTR
    dc.b    GET_NEXT_ARG_PTR
    dc.b    IS_ARG_SWITCH
    dc.b    IS_NEXT_ARG
    dc.b    GET_FILE_PTR
    dc.b    CHECK_FILE_TYPE
    dc.b    EXEC_SWITCH_ROUTINE
    dc.b    SKIP_DUMMY_LINES
    dc.b    SKIP_SPACES
    dc.b    SKIP_LINE
    dc.b    GET_FILE_HANDLE
    dc.b    GET_PREV_ARG_PTR
    dc.b    ADVANCE_TO_CHAR

PedroMCallsTable:
    dc.b    PEDROM_stdin
    dc.b    PEDROM_printf
    dc.b    PEDROM_fprintf
    dc.b    0,0
PedroMCallsOffsets:
    dc.b    STDERR
    dc.b    PRINTF
    dc.b    FPRINTF

Comme ça avec des appels en jsr non-relogés (et a6 pointeur de stack frame permanent) :
juuuuummmmmmp
		lea	CMDLINE(a6),a0				; Get CMDLINE*
		jsr	GET_NEXT_ARG_PTR(a6)			; Skip current arg
		lea	CMDLINE(a6),a0				; Get CMDLINE*
		jsr	IS_ARG_SWITCH(a6)			; Check if the arg is an switch

Vala, ça me fait tout ce que je veux sans m'embêter. On saute dans la pile et ça rebondit vers la bonne fonction de dll ou de pedrom.

Mais... comment on fait ça en C ? grin


En fait, ce que je ne sais pas faire, c'est enregistrer dans une table les offsets dans une structure (mon stack frame est une structure déclarée extern).
Si j'ai ça : typedef struct machin {int a; short b; void (*bidule)();} machin;, comment connaitre l'offset de bidule pour l'enregistrer dans un tableau ? Ca correspond au label ButillibCallsOffsets.

76

t'es sur que c'est portable? parce que je connais un outil qui fait ce genre de truc, mais en asm inline grin (arm)
Lionel Debroux (./75) :
Si tu passes un jour à un langage où il n'y a pas de préprocesseur, tu verras que tu regretteras ce bon vieux préprocesseur biggrin.gif

tellement que notre produit principal passe par gcc -E avant d'être compilé grin

77

Typiquement, c'est pour éviter de faire ça :
    Data.InitCmdline = kernel_LibsPtr(Data.pdtlib, PDTLIB__INIT_CMDLINE);       // void (*func)() kernel_LibsPtr (Descriptor, #Function);
    Data.ManageArgs = kernel_LibsPtr(Data.pdtlib, PDTLIB__MANAGE_ARGS);
    Data.GetCurrentArgPtr = kernel_LibsPtr(Data.pdtlib, PDTLIB__GET_CURRENT_ARG_PTR);
    Data.SkipArgs = kernel_LibsPtr(Data.pdtlib, PDTLIB__SKIP_ARGS);

Je voudrais une table avec les numéros de fonctions :
const unsigned char PdtlibFuncs[] = {PDTLIB__INIT_CMDLINE, PDTLIB__MANAGE_ARGS, PDTLIB__GET_CURRENT_ARG_PTR, PDTLIB__SKIP_ARGS, 0, 0};


*idée*

Et si j'essayais {&Data.InitCmdline, &Data.ManageArgs, &Data.GetCurrentArgPtr, &Data.SkipArgs}; ???
J'ai juste peur que ce con reloge à mort :/ Et j'aurai des adresses de cette manière, alors que des offsets me suffiraient.
Peut-être avec une différence ? (&Data.InitCmdline - &Data) ?

78

79

error: invalid operands to binary -
cry

80

et si t'enlèves les & et caste chacun en unsigned char?

81

En fait, ça semble marcher comme ça :
    const short PdtLibOffsets[] = {(unsigned long)&Data.InitCmdline - (unsigned long)&Data,
                                   (unsigned long)&Data.ManageArgs - (unsigned long)&Data,
                                   (unsigned long)&Data.GetCurrentArgPtr - (unsigned long)&Data,
                                   (unsigned long)&Data.SkipArgs - (unsigned long)&Data};

C'est calculé en long (un cast en char me ferait perdre la partie haute des adresses, ça pourrait devenir faux), et le cast en short pour rentrer dans le tableau doit être automatique.

Merci beaucoup, c'est ton idée de cast qui m'a fait trouver ça. smile

82

confus un pointeur sur n'importe quoi est toujours un pointeur, que ça pointe sur des chars, des longs, ou du 95B.

83

Je sais, mais j'ai relu ton post à cause de ça, t'as dit de caster en unsigned char et non en unsigned char*.
Et c'est de l'arithmétique de pointeur après, je maitrise pas, je sais juste que si j'en ai vraiment besoin, ya un chapitre dans mon bouquin.
Le cast en long permet de bosser classiquement sur des entiers non signés, et ici ça me va, vu que sur TI, sizeof(long) == sizeof(void*).
ou du 95B

A la différence que là, c'est un pointeur codé sur 1 bite

84

trisotfl 1 bite suffit pour adresser... 2 cases mémoire?trioui

il faut évidemment caster en pointeur sinon ça n'a aucun sens, ma langue a fourché.

85

./83 : un signed long est signé, contrairement à un unsigned long. (oui, je sais que dit comme ça, ça a l'air idiot, mais ta remarque m'étonne)

86

Construire du code sur la pile est forcément non portable!
1. La pile n'est pas forcément exécutable. Sur les calculatrices TI HW≥2 sans HW[23]Patch, elle ne l'est pas. Sur l'iPhone/iPad non plus. Sous un OS PC moderne (versions récentes de GNU/Linux et OS X notamment, et il me semble qu'ils aient aussi quelque chose comme ça à Redmond), elle ne l'est pas par défaut, ça peut s'activer, mais ça rend le programme moins sécurisé.
2. Le code à copier sur la pile est évidemment totalement spécifique à la machine.

Tu peux allouer de la place sur la pile par exemple avec alloca, copier ces trucs là-dedans et appeler le code en le transtypant vers le bon pointeur de fonction, mais sick!
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

87

Kevin Kofler (./86) :
Tu peux allouer de la place sur la pile par exemple avec alloca, copier ces trucs là-dedans et appeler le code en le transtypant vers le bon pointeur de fonction, mais sick.gif !

En fait, je ne mets dans la pile que des pointeurs de fonction. Et après, je les appelle. J'arriverais à écrire du code dans la pile, mais je ne saurais pas l'exécuter en C.
(alors qu'en assembleur, aucun problème évidemment grin).

88

D'un autre côté, il faut choisir le langage en fonction de ce qu'on veut faire. Ne perds pas ça de vue smile

89

Pen^2 (./85) :
./83 : un signed long est signé, contrairement à un unsigned long. (oui, je sais que dit comme ça, ça a l'air idiot, mais ta remarque m'étonne)

Tu peux expliciter stp ? Je vois mal le rapport signed/unisgned avec ce que j'ai dit...

90

Folco (./83) :
Le cast en long permet de bosser classiquement sur des entiers non signés
un long, c'est un signed long.