Page 5 sur 26

Publié : lun. 05/janv./2009 20:25
par Anonyme2
Je viens de me faire un exemple avec une correction asm (modifié par la pile) et ça marche. Je vais faire des essais en modifiant la position du paramètre et en passant 2 ou 3 tableaux en paramètres.

J'ai testé aussi la solution avec une variable en datasection et ça fonctionne, c'est plus simple que de modifier la pile et le compteur interne de PB (PSO=..) qui peut évoluer (?) dans le code PB.
Là aussi je vais faire des tests avec au moins 2 ou 3 paramètres array pour voir comment ça se passe.

Je te tiens au courant.

Publié : mar. 06/janv./2009 10:40
par Progi1984
Désolé de ne pas t'avoir pu te répondre hier soir (mais l'apéro a duré plus de cinq heures finalement :D )

Je te laisse faire pour me donner la meilleure solution. Le développement ne me gène tant que cela apporte de la facilité coté utilisateur.

Merci de ton aide :)

Publié : mar. 06/janv./2009 14:18
par Anonyme2
Mon but est de laisser l'appel Purebasic avec en paramètre le tableau et pas une variable dont on passe l'adresse. Même si ça ajoute 3 ou 4 instructions asm, c'est mieux car de toute façon ces instructions existeront quand même lorsque l'on donnera l'adresse du tableau à la variable. C'est mieux en asm car c'est transparent pour l'utilisateur.

Publié : mar. 06/janv./2009 15:25
par Progi1984
Denis a écrit :Mon but est de laisser l'appel Purebasic avec en paramètre le tableau et pas une variable dont on passe l'adresse. Même si ça ajoute 3 ou 4 instructions asm, c'est mieux car de toute façon ces instructions existeront quand même lorsque l'on donnera l'adresse du tableau à la variable. C'est mieux en asm car c'est transparent pour l'utilisateur.
J'aime bien ce concept car comme tu le dis toi-même, cela reste transparent pour l'utilisateur. J'attends de tes news :)

Publié : mer. 07/janv./2009 10:13
par Progi1984
Je ne sais pas si tu as vu mais Fred t'a répondu :
http://www.purebasic.fr/english/viewtopic.php?t=35956

Publié : mer. 07/janv./2009 11:50
par Anonyme2
Oui j'ai vu.

PSn correspond au décalage des variables locales (esp évolue) augmenté de la valeur des registres sauvegardés. Cette valeur sert à corriger le déplacement avec esp pour retrouver les paramètres.

Pour moi c'est constant confimé par Fred mais il me semble avoir vu du code asm avec PSn qui variait, peut-être ai-je rêvé (?)

Je vais faire encore quelques tests et te proposer 2 solutions. Une par la pile et une par une variable en datasection (ou plusieurs selon le nombre de paramètres array()).

Publié : mer. 07/janv./2009 13:34
par Progi1984
Personnellement dans les codes ASM PB que j'ai vu, je n'ai jamais vu PSn bouger.

J'attends tes propositions. Merci beaucoup de ton aide.

Publié : mer. 07/janv./2009 19:08
par Anonyme2
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

Code : Tout sélectionner

Fonction(Param1.l, Param2.l)
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

Code : Tout sélectionner

_Pt_Tableau_1
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

Code : Tout sélectionner

_Pt_Tableau_1:
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é.

Publié : mer. 07/janv./2009 19:33
par Anonyme2
Premier exemple :

Code PB

Code : Tout sélectionner

ProcedureDLL S08_GetVarL(Num.l, Array MyArrayL.l(1))
	ProcedureReturn MyArrayL(Num)
EndProcedure
Voila le code ASM d'origine

Code : Tout sélectionner

format MS COFF

public PB_S08_GetVarL


_Procedure0:
PB_S08_GetVarL:

PUSH   ebp
PUSH   ebx
PS0=16
XOR    eax,eax
PUSH   eax
MOV    eax,dword [esp+PS0+4]
MOV    dword [esp+0],eax
MOV    ebx,dword [esp+PS0+0]
MOV    edx,[esp+0]
MOV    ebp,dword [edx]
SAL    ebx,2
MOV    eax,dword [ebp+ebx]
JMP   _EndProcedure1
XOR    eax,eax
_EndProcedure1:
ADD    esp,4
POP    ebx
POP    ebp
RET    8

Voici le code asm modifié:
Le code modifié est compilable

Code : Tout sélectionner

format MS COFF

public PB_S08_GetVarL

_Procedure0:
PB_S08_GetVarL:



;////////////////////////////////////////////////
; Code PB de la fonction
; ProcedureDLL S08_GetVarL(Num.l, Array MyArrayL.l(1))
;     ProcedureReturn MyArrayL(Num)
; EndProcedure

; calcul de l'offset
;offset  = 0
;If position = 1
;   offset = 4
;Else
;   For i = 1 To (position-1)
;      offset + SizeOf(parametre(i))
;   Next i
;      offset + 4
;EndIf

; Position = 2
; Le calcul à la main donne 8
Offset = 8
MOV  edx, dword [esp+Offset]
; on écrit la valeur
MOV    dword [_Pt_Tableau_1], edx
MOV  dword [esp+Offset], _Pt_Tableau_1
;////////////////////////////////////////////////





PUSH   ebp
PUSH   ebx
PS0=16
XOR    eax,eax
PUSH   eax
MOV    eax,dword [esp+PS0+4]
MOV    dword [esp+0],eax
MOV    ebx,dword [esp+PS0+0]
MOV    edx,[esp+0]
MOV    ebp,dword [edx]
SAL    ebx,2
MOV    eax,dword [ebp+ebx]
JMP   _EndProcedure1
XOR    eax,eax
_EndProcedure1:
ADD    esp,4
POP    ebx
POP    ebp
RET    8



;////////////////////////////////////////////////
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
;////////////////////////////////////////////////
et le code PB d'essai

Code : Tout sélectionner

Dim AnyArrayL.l(11)

For i = 0 To 10
     AnyArrayL(i) = i*10
Next


For i = 0 To 10
   Debug S08_GetVarL(i, AnyArrayL())
Next

Publié : mer. 07/janv./2009 19:51
par Anonyme2
Deuxième exemple :
3 tableaux en paramètres

Code PB

Code : Tout sélectionner

ProcedureDLL S08_GetVarL_2(Array MyArrayL.l(1), Num.l, Array MyArrayL_1.l(1), Array MyArray_2_L.l(1))
	ProcedureReturn MyArrayL(Num) + MyArrayL_1(Num) + MyArray_2_L.l(Num)
EndProcedure
Voila le code ASM d'origine

Code : Tout sélectionner

format MS COFF

public PB_S08_GetVarL_2


_Procedure4:
PB_S08_GetVarL_2:

PUSH   ebp
PUSH   ebx
PUSH   edi
PS4=28
XOR    eax,eax
PUSH   eax
PUSH   eax
PUSH   eax
MOV    eax,dword [esp+PS4+0]
MOV    dword [esp+0],eax
MOV    eax,dword [esp+PS4+8]
MOV    dword [esp+4],eax
MOV    eax,dword [esp+PS4+12]
MOV    dword [esp+8],eax
MOV    ebx,dword [esp+PS4+4]
MOV    edx,[esp+0]
MOV    ebp,dword [edx]
SAL    ebx,2
MOV    ebx,dword [ebp+ebx]
MOV    edi,dword [esp+PS4+4]
MOV    edx,[esp+4]
MOV    ebp,dword [edx]
SAL    edi,2
ADD    ebx,dword [ebp+edi]
MOV    edi,dword [esp+PS4+4]
MOV    edx,[esp+8]
MOV    ebp,dword [edx]
SAL    edi,2
ADD    ebx,dword [ebp+edi]
MOV    eax,ebx
JMP   _EndProcedure5
XOR    eax,eax
_EndProcedure5:
ADD    esp,12
POP    edi
POP    ebx
POP    ebp
RET    16

Voici le code asm modifié:
Le code modifié est compilable

Code : Tout sélectionner

format MS COFF

public PB_S08_GetVarL_2


_Procedure4:
PB_S08_GetVarL_2:



;////////////////////////////////////////////////
; Code PB de la fonction
; ProcedureDLL S08_GetVarL_2(Array MyArrayL.l(1), Num.l, Array MyArrayL_1.l(1), Array MyArray_2_L.l(1))
; 	ProcedureReturn MyArrayL(Num) + MyArrayL_1(Num) + MyArray_2_L.l(Num)
; EndProcedure

; calcul de l'offset du premier tableau
;--------------------------------------
;offset  = 0
;If position = 1
;   offset = 4
;Else
;   For i = 1 To (position-1)
;      offset + SizeOf(parametre(i))
;   Next i
;      offset + 4
;EndIf

; Position = 1
; Le calcul à la main donne 4
Offset = 4
MOV  edx, dword [esp+Offset]
; on écrit la valeur
MOV    dword [_Pt_Tableau_1], edx
MOV  dword [esp+Offset], _Pt_Tableau_1
;
; Fin des instructions pour le premier tableau
;--------------------------------------


; calcul de l'offset du second tableau
;--------------------------------------
; Position = 3
; Taille du 1er paramètre 4 et taille du second 4 octets
; Le calcul à la main donne 12
Offset = 12
MOV  edx, dword [esp+Offset]
; on écrit la valeur
MOV    dword [_Pt_Tableau_2], edx
MOV  dword [esp+Offset], _Pt_Tableau_2
;
; Fin des instructions pour le second tableau
;--------------------------------------


; calcul de l'offset du troisième tableau
;--------------------------------------
; Position = 4
; Taille du 1er paramètre 4, taille du second 4 et taille du 3eme 4 octets
; Le calcul à la main donne 16
Offset = 16
MOV  edx, dword [esp+Offset]
; on écrit la valeur
MOV    dword [_Pt_Tableau_3], edx
MOV  dword [esp+Offset], _Pt_Tableau_3
;
; Fin des instructions pour le troisième tableau
;--------------------------------------
;////////////////////////////////////////////////






PUSH   ebp
PUSH   ebx
PUSH   edi
PS4=28
XOR    eax,eax
PUSH   eax
PUSH   eax
PUSH   eax
MOV    eax,dword [esp+PS4+0]
MOV    dword [esp+0],eax
MOV    eax,dword [esp+PS4+8]
MOV    dword [esp+4],eax
MOV    eax,dword [esp+PS4+12]
MOV    dword [esp+8],eax
MOV    ebx,dword [esp+PS4+4]
MOV    edx,[esp+0]
MOV    ebp,dword [edx]
SAL    ebx,2
MOV    ebx,dword [ebp+ebx]
MOV    edi,dword [esp+PS4+4]
MOV    edx,[esp+4]
MOV    ebp,dword [edx]
SAL    edi,2
ADD    ebx,dword [ebp+edi]
MOV    edi,dword [esp+PS4+4]
MOV    edx,[esp+8]
MOV    ebp,dword [edx]
SAL    edi,2
ADD    ebx,dword [ebp+edi]
MOV    eax,ebx
JMP   _EndProcedure5
XOR    eax,eax
_EndProcedure5:
ADD    esp,12
POP    edi
POP    ebx
POP    ebp
RET    16





;////////////////////////////////////////////////
Macro align value { rb (value-1) - ($-_S08_GetVarL_2 + value-1) mod value }

section '.Tableau' readable writeable
_S08_GetVarL_2:
align 4
_Pt_Tableau_1:
rd     1
_Pt_Tableau_2:
  rd     1
_Pt_Tableau_3:
  rd     1
;////////////////////////////////////////////////
et le code PB d'essai

Code : Tout sélectionner

Dim AnyArrayL.l(11)
Dim AnyArrayL_1.l(11)
Dim AnyArrayL_2.l(11)

For i = 0 To 10
     AnyArrayL(i) = i*10
      AnyArrayL_1(i) = i*100
      AnyArrayL_2(i) = i*5
Next

Debug ""
For i = 0 To 10
   Debug S08_GetVarL_2(AnyArrayL(), i, AnyArrayL_1(), AnyArrayL_2())
Next
Je ne sais pas si tu as assez d'exemples ?

Publié : mer. 07/janv./2009 23:15
par Progi1984
@Denis :
Je ne sais pas si tu te rends compte mais tu es génial. Je viens de passer à peine une heure pour adapter tes explications à mon code et intégrer la notions de tableaux en paramètre.

Félicitations :)

@All :
Release de la 0.5 :

Code : Tout sélectionner

    * ADDED : Parameter with default value
    * ADDED : Parameter with type : linked list
    * ADDED : Parameter with type : tables 

    * IMPROVED : Deleting of content of directories (!now : Deleting recursively main directory)
    * IMPROVED : Clearing ASM Codes (a lot of newlines)
    * IMPROVED : Step 2 : in first function, moving asm detection code to second function 

    * DONE : Tests with all Samples
La dernière source est là : http://code.google.com/p/moebius-pb/dow ... us_0.5.zip

Publié : jeu. 08/janv./2009 6:06
par Anonyme2
Progi1984 a écrit :@Denis :
Je ne sais pas si tu te rends compte mais tu es génial. Je viens de passer à peine une heure pour adapter tes explications à mon code et intégrer la notions de tableaux en paramètre.
Faut pas exagérer :)

Je me demande qu'elles sont les limites en codage PB pour une librairie, le fait que Fred passe l'adresse du tableau au lieu d'un pointeur.

Pour ton exemple 08, voici ce que ça donne les modifs par la pile, il y a un peu plus de modifs et on doit modifier PSn.

Code asm d'origine:

Code : Tout sélectionner

format MS COFF

public PB_S08_GetVarL


_Procedure0:
PB_S08_GetVarL:

PUSH   ebp
PUSH   ebx
PS0=16
XOR    eax,eax
PUSH   eax
MOV    eax,dword [esp+PS0+0]
MOV    dword [esp+0],eax
MOV    ebx,dword [esp+PS0+4]
MOV    edx,[esp+0]
MOV    ebp,dword [edx]
SAL    ebx,2
MOV    eax,dword [ebp+ebx]
JMP   _EndProcedure1
XOR    eax,eax
_EndProcedure1:
ADD    esp,4
POP    ebx
POP    ebp
RET    8
et le code modifié:

Code : Tout sélectionner

format MS COFF

public PB_S08_GetVarL


_Procedure0:
PB_S08_GetVarL:


;////////////////////////////////////////////
; ajouté
; on met sur la pile la valeur passée en paramètre
; qui est l'adresse du tableau
PUSH   dword [esp+4]
; on charge dans edx l'adresse de la pile ou l'on vient de mettre la valeur
LEA  edx, [esp]
; on écrase le paramètre Tableau par l'adresse calculée dans edx
MOV    dword [esp+8], edx
;////////////////////////////////////////////





PUSH   ebp
PUSH   ebx


;////////////////////////////////////////////
; on modifie PS0 (on ajoute 4 pour chaque parametre array)
PS0=16+4     ; PS0=16  --> + 4 car on a empilé un long sur 4 octets
;////////////////////////////////////////////



XOR    eax,eax
PUSH   eax                    
MOV    eax,dword [esp+PS0+0]  
MOV    dword [esp+0],eax 
MOV    ebx,dword [esp+PS0+4]
MOV    edx,[esp+0]          
MOV    ebp,dword [edx]      
SAL    ebx,2
MOV    eax,dword [ebp+ebx]
JMP   _EndProcedure1
XOR    eax,eax
_EndProcedure1:
ADD    esp,4
POP    ebx
POP    ebp



;////////////////////////////////////////////
; on ajuste le pointeur de pile
; la valeur à mettre dans esp est:
; nombre param array multiplié par 4
; ici 1 x 4 = 4
ADD    esp,4
;////////////////////////////////////////////


RET    8

Publié : jeu. 08/janv./2009 10:02
par Progi1984
Je fais la modification dans le code ce midi et je mets à jour le SVN & le package à ton intention :).

Publié : jeu. 08/janv./2009 11:04
par Anonyme2
N'utilises pas le code modifiant la pile, c'est juste pour montrer, car je n'ai pas mis d''exemple avec plusieurs tableaux et je n'ai pas expliqué comment faire.

Publié : jeu. 08/janv./2009 11:20
par Progi1984
Ah oki ! J'avais pas compris que c'était juste pour me montrer lol.

Donc mieux vaut il que je laisse avec la modif par une variable en datasection ou que j'utilise par modif de la pile ?