Finalement c'est un peu plus simple avec la datasection, alors je ne propose pas la modif de pile.
Ces modifs n'entrainent pas de modification de ton fichier descripteur.
Pour commencer , je vais rappeler comment sont empilés les paramètres lors de l'appel d'une fonction en StdCall.
On prend un exemple avec 2 paramètres de type long
L'empilement se fait en commençant par le dernier paramètre, ici Param2 en 32 bits, ce n'est pas comme ça en 64 bits.
On empile
Param2
On empile
Param1
Puis l'adresse de retour de la procédure va être empilée.
Lorsque l'on est sur la 1ere instruction de la procédure, le registre esp pointe l'adresse de retour, schématiquement c'est comme ça (la représentation est à l'envers car lorsque l'on empile un élément, esp décroit, c'est juste une représentation).
Code : Tout sélectionner
_____________
| |
| xxxx | <-- ESP pointe l'adresse ou est stocké l'adresse de retour
|_____________| (4 octets)
| |
| xxxx | <-- à ESP + 4 on a le 1er paramètre
|_____________|
| |
| xxxx | <-- à ESP + 8 on a le 2eme paramètre
|_____________|
Pour Moebius, on va ajouter 3 instructions asm (par tableau passé en paramètre) tout au début, avant la 1ere instruction asm PB, c'est-à-dire immédiatement après l'étiquette PB_S08_GetVarL: , celle qui définie le début du code.
Après la dernière instruction asm PB (qui est un RET avec une valeur après comme RET 4), on va écrire une Macro d'alignement et écrire la datasection avec notre ou nos variable's) utilisée(s) pour corriger.
Il y a autant de variables (Long) que de paramètres Array.
Le principe :
On crée une variable en DataSection, c'est une variable globale mais qui n'est connue que de la Procedure, elle n'est pas public.
Le code asm ajouté charge dans le registre edx (registre volatile donc utilisable sans problème) la valeur du paramètre Array qui est réellement l'adresse du tableau.
Puis on écrit dans la variable en DataSection, cette valeur.
Ensuite, le paramètre correspondant au tableau est modifié pour recevoir l'adresse de la variable en datasection.
Tout ça est fait en 3 instructions.
Voici un exemple pour le code PB suivant :
Code : Tout sélectionner
ProcedureDLL S08_GetVarL(Num.l, Array MyArrayL.l(1))
ProcedureReturn MyArrayL(Num)
EndProcedure
Le problème numéro un est de trouver la position du paramètre, Moebius le fait, donc pas de problème.
Dans l'exemple, le paramètre est à la position 2 (2eme paramètre).
Dans ce cas, le déplacement à ajouter à esp pour retomber sur le 2eme paramètre vaut +8. Je mettrais la formule pour calculer cet offset un peu après.
D'ou les instructions asm suivantes en considérant que la variable en datasection s'appelle
Les 3 instructions asm deviennent :
Code : Tout sélectionner
Offset = 8 ; notre décalage à ajouter à esp
; on charge dans edx la valeur du 2eme paramètre
MOV edx, dword [esp+Offset]
; on écrit la valeur dans notre variable
MOV dword [_Pt_Tableau_1], edx
; on modifie le paramètre en y écrivant l'adresse de la variable en datasection
MOV dword [esp+Offset], _Pt_Tableau_1
Calcul de l'offset :
Un élément que je n'ai pas évoqué c'est la taille des paramètres.
tous les paramètres ont un taille de 4 octets sauf les paramètres quad et les double. Les byte, word etc sont passés comme des paramètres ayant une taille de 4 octets.
Pour calculer l'offset, il faut avoir la position du paramètre tableau et la taille des paramètres qui précèdent.
Voilà sous forme de If / EndIf comment calculer
Position vaut la position du paramètre Array
offset est la valeur à trouver
Code : Tout sélectionner
offset = 0
If position = 1
offset = 4
Else
For i = 1 To (position-1)
offset + SizeOf(parametre(i))
Next i
offset + 4
EndIf
Les 3 instructions asm seront insérées pour chaque tableau passé en paramètre avec l'offset correspondant à chaque position du paramètre tableau.
L'adresse _Pt_Tableau_1 évoluera pour chaque paramètre en modifiant le 1 en 2 pour le 2eme tableau, en 3 pour le 3eme tableau, c'est pas très difficile.
Code : Tout sélectionner
_Pt_Tableau_1
_Pt_Tableau_2 ; 2eme tableau
_Pt_Tableau_3 ; 3eme tableau
_Pt_Tableau_n ; n ieme tableau
Maintenant, après la dernière instruction asm PB (le RET), on va écrire une macro (une seule même si il y a plusieurs tableaux en paramètre, cette macro alignera les données su 32 bits).
Voilà exactement le code:
Code : Tout sélectionner
Macro align value { rb (value-1) - ($-_S08_GetVarL + value-1) mod value }
La seule chose à modifier, c'est _S08_GetVarL qui fait référence à une étiquette, j'ai choisi ça car c'est l'étiquette de la fonction avec un _ devant
Et maintenant voici la datasection pour un seul tableau en paramètre, datasection qui est en lecture/écriture.
Il y a une première étiquette que je viens d'expliquer, elle est utilisée par la macro
Il y a ensuite l'appel de la macro d'alignement sur 32 bits (=4 octets)
Il y a ensuite l'étiquette
Puis la réservation d'un long pour la variable.
Le code de la datasection précédée de la macro devient :
Code : Tout sélectionner
Macro align value { rb (value-1) - ($-_S08_GetVarL + value-1) mod value }
section '.Tableau' readable writeable
_S08_GetVarL:
align 4
_Pt_Tableau_1:
rd 1
Si on a 3 tableaux en paramètres, ça devient
Code : Tout sélectionner
section '.Tableau' readable writeable
_S08_GetVarL:
align 4
_Pt_Tableau_1:
rd 1
_Pt_Tableau_2:
rd 1
_Pt_Tableau_3:
rd 1
La datasection s'appelle .Tableau, tu peux utiliser ce même nom pour chaque fonction car c'est une section locale (encapsulée) sans référence externe, il ne devrait pas y avoir de problèmes avec FASM.
J'arrête là pour les explications, je vais poster ce soir un ou deux exemples avec le code asm modifié.