PB-ASM-Output-Fragen

Für allgemeine Fragen zur Programmierung mit PureBasic.
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

PB-ASM-Output-Fragen

Beitrag von GPI »

In englischen Forum hat falsam einen recht interessanten Code zur Userlib-Erzeugung aus PB heraus gezeigt.
Die Prinzipielle Idee würde ich gerne in meinen Pre-Compiler einbauen. Blöd ist, das ich keinerlei Assembler kann (also zumindest x86,x64). Ich hätte aber ein paar fragen zu den Output, die der PBCompiler so erzeugt (kommentierter ASM Output bei DLL erstellung).

Meine kleine PB-Datei:

Code: Alles auswählen

Procedure test()
b+10
EndProcedure
a=10
a=a+10
a+20
test()

procedure test2()
endprocedure
Jetzt Stückweise der Output:
Der erste Block darf natürlich nicht verändert werden:

Code: Alles auswählen

; 
; PureBasic 5.61 (Windows - x64) generated code
; 
; (c) 2016 Fantaisie Software
; 
; The header must remain intact for Re-Assembly
; 
; :DLL
; :System
; kernel32.lib
; :Import
; 
format MS64 COFF
; 
; 
extrn GetModuleHandleW
extrn HeapCreate
extrn HeapDestroy
extrn memset
public _PB_Instance
public PB_ExecutableType
public PB_OpenGLSubsystem
public _PB_MemoryBase
public PB_Instance
public PB_MemoryBase
public PB_EndFunctions
public _DLLEntryPoint@12

macro pb_public symbol
{
  public  _#symbol
  public symbol
_#symbol:
symbol:
}

macro    pb_align value { rb (value-1) - ($-_PB_DataSection + value-1) mod value }
macro pb_bssalign value { rb (value-1) - ($-_PB_BSSSection  + value-1) mod value }

; 
section '.code' code readable executable align 4096
; 
; 
_DLLEntryPoint@12: ist wohl der DLL-Startpunkt, der einige PB-DLL-Sachen erledigt. Für eine Userlibrary völlig uninteressant und kann gelöscht werden, oder?

Code: Alles auswählen

_DLLEntryPoint@12:
  SUB    rsp,40
  CMP    rdx,1
  JNE   .SkipProcessAttach
  MOV    [_PB_Instance],rcx
  CALL   PB_DllInit
  JMP   .End
.SkipProcessAttach:
  CMP    rdx,2
  JNE   .SkipThreadAttach
  JMP   .End
.SkipThreadAttach:
  CMP    rdx,0
  JNE   .SkipProcessDetach
  CALL  _PB_EOP
  JMP   .End
.SkipProcessDetach:
  CMP    rdx,3
  JNE   .SkipThreadDetach
.SkipThreadDetach:
.End:
  MOV    rax,1
  ADD    rsp,40
  RET

Jetzt wirds interessant. PB_DLLInit ist wohl wichtig. Hier wurden alle Befehle gesammelt, die in Hauptquellcode vorkommen - den es in einer DLL nicht gibt. Man sieht auch das in den (von mir ausgeschnittenen Code) diese Function gestartet wird. Der Anfang scheint mir aber gefährlich.
Sub rsp,40
Scheint irgendwelche Stack-Aufräum-Aktion zu sein. Das muss bleiben
XOR r8,r8
MOV rdx,4096
XOR rcx,rcx
CALL HeapCreate
MOV [PB_MemoryBase],rax

scheint ein Funktionsaufruf zu sein, der in einer UserBibliothek garantiert nichts zu suchen hat. dementsprechend

Die zeilen drin

Code: Alles auswählen

PB_DllInit:
  SUB    rsp,40
das jetzt raus

Code: Alles auswählen

  XOR    r8,r8
  MOV    rdx,4096
  XOR    rcx,rcx
  CALL   HeapCreate
  MOV    [PB_MemoryBase],rax
und hier muss wieder drin bleiben:

Code: Alles auswählen

;; a=10
  MOV    qword [v_a],10
; a=a+10
  ADD    qword [v_a],10
; a+20
  ADD    qword [v_a],20
; test()
  CALL  _Procedure0
; 
; 
  ADD    rsp,40
  RET
_PB_EOP ist auch etwas und PB_EndFunctions sind wohl interne Funktionen, die wir in der UserLibrary auch nicht brauchen (PB-Internes Zeug entladen, oder? das macht wohl das Hauptprogramm)

Also der Part weg:

Code: Alles auswählen

_PB_EOP:
  SUB    rsp,40
  CALL   PB_EndFunctions
  MOV    rcx,[PB_MemoryBase]
  CALL   HeapDestroy
  ADD    rsp,40
  RET
PB_EndFunctions:
  SUB    rsp,40
  ADD    rsp,40
  RET
Bleibt der Rest, der unbedingt in die Userlib rein soll:

Code: Alles auswählen

; 
; Procedure test()
_Procedure0:
  PUSH   r15
  PS0=64
  XOR    rax,rax
  PUSH   rax
  SUB    rsp,40
; b+10
  MOV    r15,qword [rsp+40]
  ADD    r15,10
  MOV    qword [rsp+40],r15
; EndProcedure
_EndProcedureZero1:
  XOR    rax,rax
_EndProcedure1:
  ADD    rsp,48
  POP    r15
  RET
; 
section '.data' data readable writeable
; 
_PB_DataSection:
PB_OpenGLSubsystem: db 0
pb_public PB_DEBUGGER_LineNumber
  dd     -1
pb_public PB_DEBUGGER_IncludedFiles
  dd     0
pb_public PB_DEBUGGER_FileName
  db     0
pb_public PB_Compiler_Unicode
  dd     1
pb_public PB_Compiler_Thread
  dd     0
pb_public PB_Compiler_Purifier
  dd     0
pb_public PB_Compiler_Debugger
  dd     0
PB_ExecutableType: dd 0
pb_align 8
pb_align 8
pb_align 8
s_s:
  dq     0
  dq     -1
pb_align 8
; 
section '.bss' readable writeable
_PB_BSSSection:
pb_bssalign 8
; 
I_BSSStart:
_PB_MemoryBase:
PB_MemoryBase: rq 1
_PB_Instance:
PB_Instance: rq 1
PB_ExitCode: rq 1
; 
pb_bssalign 8
PB_DataPointer rq 1
v_a rq 1
pb_bssalign 8
pb_bssalign 8
pb_bssalign 8
pb_bssalign 8
I_BSSEnd:
section '.data' data readable writeable
SYS_EndDataSection:
Sind meine Gedankengänge richtig? Setzt PB bei jeder DLL in der DLL_INIT() ein "HeapCreate"? Ist der Funktionsmäßig immer so aufgebaut? Das würde mir die Erstellung der Userlibrary gewaltig vereinfachen.

Bonusfrage:
Oben ist ja x64, unter x86 siehts so aus:

Code: Alles auswählen

PB_DllInit:
  PUSH   dword 0
  PUSH   dword 4096
  PUSH   dword 0
  CALL  _HeapCreate@12
  MOV    [PB_MemoryBase],eax
;; a=10
Hier muss auch die drei PUSH +Call+MOV-Befehl an Anfang weg, oder?
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Benutzeravatar
RSBasic
Admin
Beiträge: 8022
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: PB-ASM-Output-Fragen

Beitrag von RSBasic »

Helle, der Assembler-Master, war seit einem Monat nicht mehr online. Mal schauen, wann er online kommt. Er kann dir auf jeden Fall helfen.
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Benutzeravatar
mk-soft
Beiträge: 3695
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: PB-ASM-Output-Fragen

Beitrag von mk-soft »

Bei DLL´s keinen Code ausserhalb von Prozeduren schreiben!!!

Der Code landet zwar in der Procedure PB_DllInit. Kann aber bei Codes ausserhalb von Prozeduren zu Stack Probleme führen.
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
Bisonte
Beiträge: 2427
Registriert: 01.04.2007 20:18

Re: PB-ASM-Output-Fragen

Beitrag von Bisonte »

mk-soft hat geschrieben:Bei DLL´s keinen Code ausserhalb von Prozeduren schreiben!!!

Der Code landet zwar in der Procedure PB_DllInit. Kann aber bei Codes ausserhalb von Prozeduren zu Stack Probleme führen.
Oh ja, das macht er auch. Mit MLF hab ich ausserhalb der Proceduren Global NewMap... gehabt, Absturz bei Aufruf.
PureBasic 6.04 LTS (Windows x86/x64) | Windows10 Pro x64 | Asus TUF X570 Gaming Plus | R9 5900X | 64GB RAM | GeForce RTX 3080 TI iChill X4 | HAF XF Evo | build by vannicom​​
Benutzeravatar
mk-soft
Beiträge: 3695
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: PB-ASM-Output-Fragen

Beitrag von mk-soft »

Es reicht

Code: Alles auswählen

Procedure MyInit()
  ; Code
EndProcedure : MyInit()
auch wenn es nicht Dokumentiert ist. Wichtig beim schreiben von Modulen mit automatischer Initialisierung.
Wird genauso behandelt als ob der Code in der ProcedureDLL AttachProcess(instance). Aber ohne den Parameter 'instance'
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Re: PB-ASM-Output-Fragen

Beitrag von GPI »

Bisonte hat geschrieben:
mk-soft hat geschrieben:Bei DLL´s keinen Code ausserhalb von Prozeduren schreiben!!!

Der Code landet zwar in der Procedure PB_DllInit. Kann aber bei Codes ausserhalb von Prozeduren zu Stack Probleme führen.
Oh ja, das macht er auch. Mit MLF hab ich ausserhalb der Proceduren Global NewMap... gehabt, Absturz bei Aufruf.
Warum MLF abstürzt kann ich dir sagen: Sämtlicher Code außerhalb der Proceduren werden von MLF vollständig ignoriert! Ich möchte das vermeiden. PB sammelt ja auch den Code außerhalb der Proceduren bei einer DLL und sammelt ihn in DLLinit. Das würde vieles vereinfachen.

Mein PreCompiler nutzt was ähnliches - es erstellt einen INIT-Procedure und ruft diese außerhalb auf. Bei DLLs werden die ja gesammelt.

Ich denke, das ist ein guter Kompromiss:
Ich werd einfach alle "Calls _procedure<nb>" zwischen "PB_DllInit:" und RET einsammeln und in Quellcode eine versteckte

Code: Alles auswählen

ProcedureDLL Initalize()
EndProcedure
einfügen

in asmcode wird das dann ein

Code: Alles auswählen

; ProcedureDLL Initalize()
_Procedure4:
  PS4=48
  SUB    rsp,40
; EndProcedure
_EndProcedureZero5:
  XOR    rax,rax
_EndProcedure5:
  ADD    rsp,40
  RET
und hier vor ;EndProcedure die ganzen Calls einfügen (haben ja alle keinen Parameter) und diese Initalize-Procedure als InitFunction (oder wie das gleich heißt) eintragen.
Wenn eine Procedure keinen Parameter hat, braucht man ja nichts beachten, nur calls. Obs Parameter hat, kann der Precompiler feststellten.

Das sollte klappen. Es ist leider, gerade wenn man mit Modulen arbeitet, nicht immer einfach eine globale "Initalize"-Routine zu schreiben. Es widerspricht auch den Grundgedanken von Modulen.
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Benutzeravatar
mk-soft
Beiträge: 3695
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: PB-ASM-Output-Fragen

Beitrag von mk-soft »

Man brauch nicht den ASM-Code anpassen.
Der Compiler packt alles in der richtigen Reihenfolge in die PB_DllInit. Die Initialisierung von List und Map funktionieren als Strukturen auch einwandfrei.

Sonst würde mein Modul 'Modul_BaseClassDispatch' keine funktionierende COM-DLL´s mit später Bindung erstellen.

Diesen Aufbau habe ich über ASM in verschiedenen Konfigurationen getestet.
Leider habe ich von PB-Team noch keine offizielle Antwort bekommen.

Code: Alles auswählen

DeclareModule MyModule
  ; Structs ...
  Structure sMyPublicData
    MyText.s
    List MyList.s()
    Map MyMap.i()
  EndStructure
  
  ; Declare ...
  
EndDeclareModule

Module MyModule
  
  Structure sMyPrivateData
    MyText.s
    List MyList.s()
    Map MyMap.i()
  EndStructure
  
  Global MyPrivateData.sMyPrivateData
  
  Procedure InitModule()
    ; Code  
  EndProcedure : InitModule()
  
EndMacro
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Re: PB-ASM-Output-Fragen

Beitrag von GPI »

mk-soft hat geschrieben:Man brauch nicht den ASM-Code anpassen.
Wenn du eine Userlib erstellen willst (schau mal in tips&tricks in Englischen Forum) dann schon. Dann wird nämlich die DLL-Init nie angesprochen.
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Antworten