externe Funktionsdeklaration in MASM
-
mhh.. (Borland) Delphi arbeitet doch mit fastcall !?.
-
masm unterstützt fastcall nicht, jwasm(masm clon) aber schon.
Die Deklaration müsste dann so aussehen:
SetLen PROTO FASTCALL bla:ptr BYTE,val:BYTEEin andere Möglichkeit wäre es, wenn du die calling convention in delphie zu z.B. sdtcall änderst.
-
x86-64 schrieb:
masm unterstützt fastcall nicht, jwasm(masm clon) aber schon.
Die Deklaration müsste dann so aussehen:
SetLen PROTO FASTCALL bla:ptr BYTE,val:BYTEEin andere Möglichkeit wäre es, wenn du die calling convention in delphie zu z.B. sdtcall änderst.
Hallo und Danke für eure Antworten.
1. Delphi hat nicht mehr Pascal als Standardaufrufkonvention, sondern Register. Dies entspricht am ehesten dem, was in C/C++ der fastcall ist. Die Parameter werden in Reihenfolge ins EAX, EDX und ECX Register gelegt.
2. Ich kann die Aufrufkonvention in Delphi sogar in CDECL ändern; aber natürlich nicht von den bereits bestehenden Funktionen (wie eben SetLength). Die ist weiterhin Register.
Ich vermute jetzt mal, dass die Meldung nicht wirklich daraufhin deutet, dass er nur differierende Calling Conventions gefunden hat, aber in Delphi weiß man ja nie
Ich schaue es mir mal an.
-
So,
ich hab jetzt einfach mal versucht mit meinem eigenen (zunächst simplen) Code-Implementationen weiter zu machen.
Ich glaube mir reicht das Hilfe-Dokument allein nicht aus; dass hat ja stellenweiße nicht mehr viel mit Assembler zu tun, was da gemacht wird.
Wie genau implementiere ich jezt eine Funktion? Angenommen ich habe eine Funktion IntCmp, die aus einem C-Programm aufgerufen werden soll. Ich bin da jetzt folgendermaßen drangegangen:
TITLE Compare.asm .686P .XMM .MODEL FLAT, C PUBLIC IntCmp:PROC .CODE _TEXT SEGMENT _lho$ = 8 _rho$ = 12 _dwSize$ = 16 IntCmpEx PROC push edi push esi push ebx xor ebx, ebx test ecx, 0xFFFFFFFC lea esi, DWORD PTR [eax+ecx-1] lea edi, DWORD PTR [edx+ecx-1] jz Bytes sub esi, 3 sub edi, 3 DWORDs: mov eax, DWORD PTR [esi] mov edx, DWORD PTR [edi] cmp eax, edx jnz Exit sub esi, 4 sub edi, 4 sub ecx, 4 test ecx, 0xFFFFFFFC jnz DWORDs test ecx, ecx jz Exit add esi, 3 add edi, 3 Bytes: movzx eax, BYTE PTR [esi] movzx edx, BYTE PTR [edi] dec edi dec esi cmp eax, edx jnz Exit dec ecx jnz Bytes Exit: seta bl sbb ebx, 0 mov eax, ebx pop ebx pop esi pop edi IntCmpEx ENDP _TEXT ENDS END
Bekomme aber folgende Fehler:
(8): Error A2008 : Syntax Error : : (23): Error A2206 : Missing operator in expression (42): Error A2206 : Missing operator in expression
23 und 42 sind die Zeilen mit der Hexzahl. Wie muss ich denn Hexzahlen in MASM angeben? Mit einem nachgestellten 'h' mag er es auch nicht (unbekannter Bezeichner).
Was ich auch noch gesehen habe ist folgende Art der Funktionsdeklaration:
myproc PROC FAR C PUBLIC <callcount> USES di si, argcount:WORD, arg2:VARARG
was muss ich da denn alles angeben und vorallem: Was gibt denn USES an? Alle verwendeten Register?
-
Zu USES: Nach uses folgen Register, die automatisch beim Eintritt in die Prozedur auf den stack gepusht werden sollen. Überall wo RET oder LEAVE steht, werden dann die Argument wieder vom stack geholt (pop). Für eine normale Funktionsdefinition reicht:
Name proc Parameter1:DWORD,Parameter2:DWORD ...
DWORD = nur Beispielhaft, man könnte auch byte,word,real4,real8... verwenden.
Der Prototyp dazu sähe gleich aus, bis auf das man 'proc' durch 'proto' ersetzt.; die von masm erstellte object file (*.obj) muüsste man dem c-linker mitteilen .686P .XMM .MODEL FLAT, C IntCmpEx PROTO ;hat keine Parameter? .CODE ; zwischen den Segment wechselt man mit .code .data .data? .const start: ; _lho$ = 8 _rho$ = 12 _dwSize$ = 16 ; Allgemeiner Hinweis: ; Masm verfügt über hochsprachen Konstrukte wie .if/.eleif/.ele/.endif .while/.endw .repeat/.until .break .continue ; Bsp: .if eax >= edx && ecx != MyDwordVar ; ... ; .endif ; Vergleichsoperatorn: '!=', '<=' , '>=' , '==' ,'<' , '>' ; Sonstige: Negieren : '!' ; Bitverknüpfung : 'a&b' = A AND B ; : 'a|b' ? A OR B ; - Mehrere Bedingungen verknüpft man mit '&&' und '||' ; - Klammern kann man auch: ((a!=b) || !(b>=c)) ... ; - Flags können getestet werden: ZERO?,CARRY?,OVERFLOW? ... ; Bsp: .if !ZERO? ; wenn zero-flag nicht gesetzt ; - Es können Register, Speicheroperanten und Konstanten verglichen werden, aber nie 2 Speicheroperanten miteinaner ; - die Operanten die verglichen werden, müssen natürlich gleich groß sein ; - u.v.m. ;) IntCmpEx PROC ; hat keine Parameter ? push edi push esi push ebx xor ebx, ebx test ecx, 0FFFFFFFCh ; Zahlen dürfen nie mit Buchstaben anfangen -> 0 davor falls nötig ; hex-dezimale Zahlen haben das "h" Suffix, (binär: 'y' oder 'b') lea esi, DWORD PTR [eax+ecx-1] lea edi, DWORD PTR [edx+ecx-1] jz Bytes sub esi, 3 sub edi, 3 DWORDs: mov eax, DWORD PTR [esi] mov edx, DWORD PTR [edi] cmp eax, edx jnz Exit sub esi, 4 sub edi, 4 sub ecx, 4 test ecx, 0FFFFFFFCh jnz DWORDs test ecx, ecx jz Exit add esi, 3 add edi, 3 Bytes: movzx eax, BYTE PTR [esi] movzx edx, BYTE PTR [edi] dec edi dec esi cmp eax, edx jnz Exit dec ecx jnz Bytes Exit: seta bl sbb ebx, 0 mov eax, ebx pop ebx pop esi pop edi ret ; ohne RET wird das nichts ;) IntCmpEx ENDP END start
-
Problematisch ist bei mir gerade eher, dass ich nicht in der Lage bin die entstandene Objektdatei im Visual Studio zu linken; mit GCC geht's.
Hab das Ganze so gemacht:
#pragma comment(linker, "/include:Compare.obj") #define LPCVOID const void* extern int IntCmp(LPCVOID lho, LPCVOID rho, LPCVOID lpSize); int main(int argc, char** argv, char** env) { int i1 = 7, i2 = 9, res = 0; res = IntCmp(&i1, &i2, sizeof(i1)); return 0; }
Er sagt immer
unresolved external symbol '_IntCmp'
Zudem bekomme ich es nicht hin zwei Funktionen zu deklarieren.
TITLE SimpleTest.asm .686P .XMM .MODEL FLAT Proc1 PROTO Proc2 PROTO .CODE Proc1 PROC ; ; Proc1 ENDP Proc2 PROC ; ; Proc2 ENDP END
MASM hat damit kein Problem. So lange ich nur Proc1 hier deklariere hat Delphi nichts dagegen (in Delphi sind beide Funktionen als extern deklariert und das Obj-File gelinkt). Wenn beide drin sind, dann sagt er bei beiden ungenügende external Deklaration bzw. "Falsche globale Symboldefinition".
Was mache ich falsch?
-
Vielleicht fehlt da einfach ein extern "C":
... extern "C" { extern int IntCmp(LPCVOID lho, LPCVOID rho, LPCVOID lpSize); } ...
-
Kennst du dich vielleicht auch mit Delphi aus?
Habe ein Objekt-File, dass ich mit MASM folgendermaßen kompiliert habe:ml /c /omf "source.asm"
Das ganze habe ich dann per "{$LINK "Pfad\source.obj"} in Delphi gelinkt und bekomme aber immer die Meldung: "Falsches Dateiformat".
-
das omf-Format von Delphi weicht etwas vom Standard ab ... Im Manual zu Agner Fog's ObjConverter steht etwas dazu.
Aber warum schreibst du nicht einfach eine Dll in masm? - ist doch am einfachsten.
-
dll schrieb:
das omf-Format von Delphi weicht etwas vom Standard ab ... Im Manual zu Agner Fog's ObjConverter steht etwas dazu.
Aber warum schreibst du nicht einfach eine Dll in masm? - ist doch am einfachsten.Jo, hab ich jetzt auch gemacht. Es ist wirklich nur rum gemurkse, wenn man mit Delphi OMF-Dateien arbeiten muss. Entweder bin ich zu blöd, ... auf jeden Fall geht es mal und mal geht es nicht ... Irgendwie scheint es, wie du schon sagtes, sich nicht wirklich an den Standard zu halten.