Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

*Exe Programm aus Assembler heraus ausführen /4bh

69 views
Skip to first unread message

paran...@web.de

unread,
Jul 31, 2006, 8:34:42 AM7/31/06
to
Hallo,

ich will aus einem Assembler Programm mit der Funktion 4bh (21h) ein
(externes) Exe- Programm ausführen.

Womit ich im Moment Probleme habe, ist der Parameter Block, dessen
Offset in bx stehen muss.

Leider ist er nur in Englisch kommentiert, mein Englisch ist aber eher
schwach..


Offset Size Description

00 word when AL=1, segment of env. or zero if using parents env.
word when AL=3, segment of load point for overlay
02 dword when AL=1, pointer to cmd line at PSP 80h
word when AL=3, relocation factor for EXE overlay
06 dword pointer to default ~FCB~ passed at ~PSP~ 5Ch
0A dword pointer to default FCB passes at PSP 6Ch
0E dword value of program SS:SP
12 dword value of program CS:IP

(Quelle PCHelp 2.1, David Jurgens)


Wie genau müsste der parameter Block aussehen? Gibt es irgendein
(möglichst kleines/ einfach zu verstehendes/ deutsch kommentiertes
;-)) Beispiel, an dem ich die Funktion begreifen lernen kann?

Ich würde mich sehr freuen, wenn ihr mir weiterhelfen könntet.

MfG,

Niels

Herbert Kleebauer

unread,
Jul 31, 2006, 2:21:40 PM7/31/06
to
paran...@web.de wrote:

> Womit ich im Moment Probleme habe, ist der Parameter Block, dessen
> Offset in bx stehen muss.

Ich kann dir nur empfehlen, dir das Buch "PC Intern" von
Michael Tischer zu besorgen.

AH = 4Bh
AL = 00h
ES:BX = FAR-Zeiger auf den Parameterblock
DS:DX = FAR-Zeiger auf den Puffer mit dem Dateinamen des Programms

- Der Parameterblock muß folgendes Format haben:

Byte 0-1: Segmentadresse des Environment-Blocks
Byte 2-3: Offsetadresse der Kommandoparameter
Byte 4-5: Segmentadresse der Kommandoparameter
Byte 6-7: Offsetadresse des ersten FCB
Byte 8-9: Segmentadresse des ersten FCB
Byte 10-11: Offsetadresse des zweiten FCB
Byte 12-13: Segmentadresse des zweiten FCB

- Wird als Segmentadresse des Environment-Blocks der Wert 0 übergeben, so verfügt das aufgerufene Programm über den gleichen Environment-Block wie das aufrufende Programm.
- Die Kommandoparameter müssen im Speicher in der Art gespeichert sein, daß zunächst die Anzahl der Zeichen in der Kommandozeile als Byte abgespeichert wird. Darauf folgen die einzelnen ASCII-Zeichen, die durch ein Carriage Return (ASCII-Code 13) beendet werden. Dieses Carriage Return wird allerdings bei der Anzahl der Zeichen nicht mitgezählt.

- Der erste übergebene FCB wird ab der Adresse 5Ch, der zweite ab der Adresse 6Ch in den PSP des aufgerufenen Programms kopiert. Entnimmt das aufgerufene Programm diesen beiden FCB keine Informationen, können beliebige Werte in die FCB-Felder im Parameterblock eingetragen werden.
- Nach dem Aufruf dieser Funktion sind alle Register bis auf das CS- und das IP-Register zerstört. Ihr Inhalt sollte deshalb vor dem Funktionsaufruf gespeichert werden, um ihn nach dem Funktionsaufruf restaurieren zu können.

- Das aufgerufene Programm verfügt über alle Handles, die auch dem aufrufenden Programm zur Verfügung stehen.

paran...@web.de

unread,
Aug 1, 2006, 4:10:15 AM8/1/06
to
Hallo

vielen Dank für die Antwort, Herbert.

Ich habe versucht das ganze einmal in einem Beispielprogramm
auszuprobieren. Ausgeführt werden soll das Programm tasm.exe mit der
Option " /?".
_________________________
.model tiny
.code
org 100h
start:
mov word ptr [offset xyz],cs
lea bx, hallo
lea dx, xy
mov ah, 4bh
xor al,al
int 21

hallo dw 0
dw [offset cmd]
xyz dw,?
dw -1,-1
dw -1,-1
cmd db 03," /?",13
xy db "C:\asm\tasm.exe",0
end start
______________________________

Assembliert habe ich das ganze mit "tasm", gelinkt mit "tlink /t" und
ausgeführt unter Freedos. Herausgekommen ist folgendes: "Invalid
opcode at 0118 027a 0246 0000....


Weiss jemand, wo der Fehler liegt?
Ich wäre froh, jemand könnte mir weiterhelfen,

MfG,
Niels
( Sorry, der code ist seh unsauber und schlecht, bin noch Assembler
Anfänger)

Herbert Kleebauer

unread,
Aug 1, 2006, 1:24:11 PM8/1/06
to
paran...@web.de wrote:

Was soll dein Program nach dem int21 auch machen, es führt
den dahinter liegenden Datenbereich als Befehle aus. Kein
Wunder, daß das zu einem "Invalid opcode" führt.

Ein anderes Problem ist, daß das laufende com Programm den
gesamten Speicher (bzw. den größten freien Speicherblock)
zugewiesen bekommt. Wenn du den nicht benötigten Bereich
nicht wieder frei gibst, dürfte kaum genügend freier Speicher
vorhanden sein um ein externes Program auszuführen. Willst
du die Funktuion 4b nur mal ausprobieren oder willst du sie
tatsächlich benutzen um TASM zu starten. Im zweiten Fall
soltest du überlegen, ob nicht eine batch Datei wesentlich
einfacher wäre.

Ich hab die Fkt. 4b nur einmal benutzt als es um die Frage
ging, ob man von einem DOS com Program eine Windows Messagebox
aufrufen kann. Ich habe dazu aus dem com Programm heraus ein
Windows exe Programm geschrieben und dies dann mit 4b/int21
gestartet und anschließend wieder gelöscht:


@=$100

00000000: 00000100: b4 3c move.b #$3c,m0
00000002: 00000102: 31 c9 eor.w r2,r2
00000004: 00000104: ba 01aa move.w #fname,r1
00000007: 00000107: cd 21 trap #$21 ; Datei oeffnen (___.com)
00000009: 00000109: 72 56 bcs.b _110
0000000b: 0000010b: 89 c3 move.w r0,r3

0000000d: 0000010d: fc bclr.w #10,sr
0000000e: 0000010e: be 01c5 move.w #buf2,r5
00000011: 00000111: bf 0341 move.w #buf1,r6

00000014: 00000114: ac _10: move.b (r5.w)+-,r0
00000015: 00000115: 38 06 01c0 cmp.b r0,esc0
00000019: 00000119: 75 47 bne.b _20
0000001b: 0000011b: a4 move.b (r5.w)+-,(r6.w)+-{s1}
0000001c: 0000011c: 81 fe 0341 _100: cmp.w #buf1,r5
00000020: 00000120: 72 f2 blo.b _10
00000022: 00000122: b4 40 move.b #$40,m0
00000024: 00000124: ba 0341 move.w #buf1,r1
00000027: 00000127: 89 f9 move.w r6,r2
00000029: 00000129: 29 d1 sub.w r1,r2
0000002b: 0000012b: cd 21 trap #$21

0000002d: 0000012d: b4 3e move.b #$3e,m0
0000002f: 0000012f: cd 21 trap #$21

00000031: 00000131: b8 4a00 move.w #$4a00,r0 ; Speicher nach 64k freigeben
00000034: 00000134: bb 1000 move.w #$1000,r3
00000037: 00000137: cd 21 trap #$21

00000039: 00000139: b4 09 move.b #$09,m0 ; text ausgeben
0000003b: 0000013b: ba 0196 move.w #text,r1
0000003e: 0000013e: cd 21 trap #$21

00000040: 00000140: 8c d8 move.w s0,r0
00000042: 00000142: a3 01b6 move.w r0,p_seg
00000045: 00000145: a3 01ba move.w r0,p_f1
00000048: 00000148: a3 01be move.w r0,p_f2
0000004b: 0000014b: b8 4b00 move.w #$4b00,r0
0000004e: 0000014e: bb 01b2 move.w #par,r3
00000051: 00000151: ba 01aa move.w #fname,r1
00000054: 00000154: 1e move.w s0,-(sp)
00000055: 00000155: cd 21 trap #$21 ; ___.com starten
00000057: 00000157: 1f move.w (sp)+,s0


00000058: 00000158: b4 41 _120: move.b #$41,m0 ; ___.com loeschen
0000005a: 0000015a: ba 01aa move.w #fname,r1
0000005d: 0000015d: cd 21 trap #$21
0000005f: 0000015f: 72 f7 bcs.b _120 ; funktioniert erst, wenn ___.com beendet ist

00000061: 00000161: c3 _110: rts.w

00000062: 00000162: 3a 06 01c1 _20: cmp.b esc1,r0
00000066: 00000166: 75 05 bne.b _30
00000068: 00000168: 31 c0 eor.w r0,r0
0000006a: 0000016a: ab move.w r0,(r6.w)+-{s1}
0000006b: 0000016b: eb af br.b _100
0000006d: 0000016d: 3a 06 01c2 _30: cmp.b esc2,r0
00000071: 00000171: 75 06 bne.b _40
00000073: 00000173: 31 c0 eor.w r0,r0
00000075: 00000175: ab move.w r0,(r6.w)+-{s1}
00000076: 00000176: aa _31: move.b r0,(r6.w)+-{s1}
00000077: 00000177: eb a3 br.b _100
00000079: 00000179: 3a 06 01c3 _40: cmp.b esc3,r0
0000007d: 0000017d: 75 06 bne.b _50
0000007f: 0000017f: 31 c0 eor.w r0,r0
00000081: 00000181: ab move.w r0,(r6.w)+-{s1}
00000082: 00000182: ab move.w r0,(r6.w)+-{s1}
00000083: 00000183: eb 97 br.b _100
00000085: 00000185: 3a 06 01c4 _50: cmp.b esc4,r0
00000089: 00000189: 75 eb bne.b _31
0000008b: 0000018b: ac move.b (r5.w)+-,r0
0000008c: 0000018c: 0f b6 c8 movu.bw r0,r2
0000008f: 0000018f: 41 inc.w r2
00000090: 00000190: 31 c0 eor.w r0,r0
00000092: 00000192: f3 aa rep_r2 move.b r0,(r6.w)+-{s1}
00000094: 00000194: eb 86 br.b _100

00000096: 00000196: 63 6c 69 63 6b 20
0000009c: 0000019c: 74 68 65 20 6f 4b
000000a2: 000001a2: 20 62 75 74 74 6f
000000a8: 000001a8: 6e 24 text: dc.b "click the oK button$"
000000aa: 000001aa: 5f 5f 5f 2e 63 6f
000000b0: 000001b0: 6d 00 fname: dc.b "___.com",0
000000b2: 000001b2: 0000 par: dc.w 0
000000b4: 000001b4: 0080 dc.w $80
000000b6: 000001b6: 0000 P_seg: dc.w 0
000000b8: 000001b8: 005c dc.w $5c
000000ba: 000001ba: 0000 p_f1: dc.w 0
000000bc: 000001bc: 006c dc.w $6c
000000be: 000001be: 0000 p_f2: dc.w 0

esc:
esc0: blk.b 1 ; escape for esc0-esc4
esc1: blk.b 1 ; 2 0 bytes (esc1)
esc2: blk.b 1 ; 3 0 bytes (esc2)
esc3: blk.b 1 ; 3 0 bytes (esc3)
esc4: blk.b 1 ; n 0 bytes (esc4 n)

buf2: blk.b 385-5 ; ACHTUNG: richtig Laenge einsetzen
buf1:

Sebastian Biallas

unread,
Aug 1, 2006, 1:22:38 PM8/1/06
to
Herbert Kleebauer wrote:
> @=$100
>
> 00000000: 00000100: b4 3c move.b #$3c,m0

Was sind denn das für krasse x86-Mnemonics? Ist ja noch eine Spur
ekelhafter als der AT&T-Style.

--
Gruß,
Sebastian

paran...@web.de

unread,
Aug 1, 2006, 1:47:27 PM8/1/06
to

> Herbert Kleebauer schrieb:

> Was soll dein Program nach dem int21 auch machen, es führt
> den dahinter liegenden Datenbereich als Befehle aus. Kein
> Wunder, daß das zu einem "Invalid opcode" führt.
>
> Ein anderes Problem ist, daß das laufende com Programm den
> gesamten Speicher (bzw. den größten freien Speicherblock)
> zugewiesen bekommt. Wenn du den nicht benötigten Bereich
> nicht wieder frei gibst, dürfte kaum genügend freier Speicher
> vorhanden sein um ein externes Program auszuführen. Willst
> du die Funktuion 4b nur mal ausprobieren oder willst du sie
> tatsächlich benutzen um TASM zu starten. Im zweiten Fall
> soltest du überlegen, ob nicht eine batch Datei wesentlich
> einfacher wäre.
>
> Ich hab die Fkt. 4b nur einmal benutzt als es um die Frage
> ging, ob man von einem DOS com Program eine Windows Messagebox
> aufrufen kann. Ich habe dazu aus dem com Programm heraus ein
> Windows exe Programm geschrieben und dies dann mit 4b/int21
> gestartet und anschließend wieder gelöscht:


Hallo Herbert,

vielen Dank für die Hilfe.
-Das mit dem vergessenen int21:4ch ist peinlich....
Dann wäre dieses Problem geklärt.
- Zu dem zweiten Problem: Leider ist eine Batch Datei keine
Alternative...Ich programmiere gerade einen Companion DOS- Virus (nur
zu Versuchszwecken und nur auf meinem von der Außenwelt abgeschotteten
Zweitrechner) und da wäre eine Bat Datei auffällig.
D.h. in meinem Fall, dass der Virus den Commandline- Parameter
entgegennimmt und am Schluss der *.com (des Virus) die entsprechende
*.Exe Datei (mit den entgegengenommenen Kommandooptionen) aufruft . Der
Speicher, den die *.com Datei verwendet hat kann also komplett
freigegeben werden, Register müssten auch nicht gesichert werden.

Danke auf jeden Fall, ich arbeite mal den Beispieltext durch und schaue
ob ichs begreife.

MfG,

Niels

Herbert Kleebauer

unread,
Aug 1, 2006, 2:36:34 PM8/1/06
to

Sebastian Biallas wrote:
>
> Herbert Kleebauer wrote:
> > @=$100
> >
> > 00000000: 00000100: b4 3c move.b #$3c,m0
>
> Was sind denn das für krasse x86-Mnemonics? Ist ja noch eine Spur
> ekelhafter als der AT&T-Style.

Nicht jeder is so ein extremer Masochist, daß er bereit ist eine
derartig perverse Syntax zu verwenden wie sie von ein paar
Sadisten bei Intel erdacht wurde.

Sebastian Biallas

unread,
Aug 1, 2006, 2:41:43 PM8/1/06
to

Mag sein, beantwortet meine eigentliche Frage aber nicht: Wo kommt das
her? Sieht nach missbrauchtem 68000 aus.

Im Übringen mag die x86-Architektur zwar furchtbar sein, die
Intel-Syntax hat aber so ziemlich die lesbarsten Assembler-Mnemonics,
die ich kenne.

--
Gruß,
Sebastian

Herbert Kleebauer

unread,
Aug 1, 2006, 3:51:41 PM8/1/06
to
Sebastian Biallas wrote:
> Herbert Kleebauer wrote:

> Mag sein, beantwortet meine eigentliche Frage aber nicht: Wo kommt das

In deinem letzten Posting war überhaupt keine Frage.

> her? Sieht nach missbrauchtem 68000 aus.

Was sollte daran "mißbraucht" sein? Die im Vergleich zum x86 wesentlich
"schönere" 68k Architektur gehört ja leider weitgehend der Vergangenheit
an. Aber immerhin kann man ja zumindest die logisch durchdachte 68k
Assemblersynatx (die ihren Ursprung wohl bei der PDP11 hat) beim x86
weiter verwenden (die Hardware muß man so hinnehmen wie sie ist, für
die Software gilt dies glücklicherweise nicht).


> Im Übringen mag die x86-Architektur zwar furchtbar sein, die
> Intel-Syntax hat aber so ziemlich die lesbarsten Assembler-Mnemonics,
> die ich kenne.

Genau anders herum. Seit dem 386 ist die Architektur ganz brauchbar
(war echt eine tolle Leistung was die Intel Leute aus dem 16 Bit x86
gemacht haben) nur bei der Assemblersyntax dreht es jedem logisch
Denkenden den Magen um.

mov ebx,eax; mov ecx,ebx; mov edx,ecx;

lege in den Umschlag den Brief; lege in die Sachtel den Umschlag; lege in den Safe die Schachtel;

Diese Zeile muß man fünf mal lesen um sie zu verstehen, jeder vernünftig
Mensch würde schreiben:

lege den Brief in den Umschlag; lege den Umschlag in die Schachtel; lege die Schachtel in den Safe;

move.l r0,r1; move.l r1,r2; move.l r2,r3;


Warum kann man nicht genau so wie den Speicheradressraum auch den
Registeradressraum einfach durchnummerieren? Warum benutzt man
so viele Namen (eax,ax,ah,al,ebx,bx,bh,bl,ecx,cx,ch,cl,edx,dx,dh,dl,
ebp,bp,esi,si,edi,di,esp,sp) anstatt einfach r0-r7 zu verwenden.
Glücklicherweise hat AMD die 64 Bit Erweiterung spezifiziert,
denn sonst würden wir vermutlich nochmals jede Menge Namen für
die restlichen Register haben.


Was bitte hat die Operandengröße (8, 16, 32 Bit) bei den Operanden
zu suchen? Eine 8 und eine 32 Bit Addition haben nun mal einen
unterschiedlichen Opcode, die Addressangabe unterscheidet sich dagegen
nicht. Es ist also völlig unlogisch zu schreiben:

inc byte ptr [adresse]

logisch ist:

inc.b adresse


Genau so unlogsch ist die unterschiedlich Indirektionsstufe im
Speicher- und im Registeradressraum.

Wenn ich die Zahl 5 in das Register eax schreiben will, kann ich
entweder "mov (eax),5" oder "move eax,#5" (oder wie bei GAS $5)
schreiben, aber sicherlich nicht "mov eax,5".

Und das läßt sich beliebig fortsetzen. Ich habe bisher überhaupt
noch nichts gefunden was bei der Intel Syntax auch nur annähernd
logisch ist. Und noch schlimmer wird es dann bei "High Level"
Assembleren wie MASM bei dem es dann auch noch Dinge wie PROC,
ENDPROC, ASSUME usw. gibt (von denen die CPU nun absolut keine
Ahnung hat).

Sebastian Biallas

unread,
Aug 1, 2006, 4:59:40 PM8/1/06
to
Herbert Kleebauer wrote:
> Sebastian Biallas wrote:
>> Herbert Kleebauer wrote:
>
>> Mag sein, beantwortet meine eigentliche Frage aber nicht: Wo kommt das
>
> In deinem letzten Posting war überhaupt keine Frage.

In <4j9gusF...@news.dfncis.de> steht: "Was sind denn das für krasse
x86-Mnemonics?"

Ich hab mich vielleicht etwas harsch ausgedrückt, aber die Frage war
durchaus echt gemeint.

>> her? Sieht nach missbrauchtem 68000 aus.
>
> Was sollte daran "mißbraucht" sein?

Dass die Schreibweise und Nomenklatur einer ganz anderen Architektur auf
x86 übertragen wird.

> Die im Vergleich zum x86 wesentlich
> "schönere" 68k Architektur gehört ja leider weitgehend der Vergangenheit
> an. Aber immerhin kann man ja zumindest die logisch durchdachte 68k
> Assemblersynatx (die ihren Ursprung wohl bei der PDP11 hat) beim x86
> weiter verwenden (die Hardware muß man so hinnehmen wie sie ist, für
> die Software gilt dies glücklicherweise nicht).

Dabei entstehen dann auch noch diverse Inkonsistenzen:
* cx ist eigentlich r1
* di ist eigentlich r7
* Es wird "vorgetäuscht", dass die Register omnipotent sind

>> Im Übringen mag die x86-Architektur zwar furchtbar sein, die
>> Intel-Syntax hat aber so ziemlich die lesbarsten Assembler-Mnemonics,
>> die ich kenne.
>
> Genau anders herum. Seit dem 386 ist die Architektur ganz brauchbar
> (war echt eine tolle Leistung was die Intel Leute aus dem 16 Bit x86
> gemacht haben) nur bei der Assemblersyntax dreht es jedem logisch
> Denkenden den Magen um.

Ich würde mich schon als logisch denkenden Menschen bezeichnen, und bei
mir dreht sich der Magen nicht um.

> mov ebx,eax; mov ecx,ebx; mov edx,ecx;
>
> lege in den Umschlag den Brief; lege in die Sachtel den Umschlag; lege in den Safe die Schachtel;
>
> Diese Zeile muß man fünf mal lesen um sie zu verstehen, jeder vernünftig
> Mensch würde schreiben:
>
> lege den Brief in den Umschlag; lege den Umschlag in die Schachtel; lege die Schachtel in den Safe;
>
> move.l r0,r1; move.l r1,r2; move.l r2,r3;

Ich weiß jetzt nicht genau, was Du mir sagen willst.

Bei PowerPC heißt es auch (wenn man ihn nicht mit AT&T vergewaltigt)
mr r3, r0; mr r1, r3; mr r2, r1
analog zu
r3:=r0; r1:=r3; r2:=r1;

> Warum kann man nicht genau so wie den Speicheradressraum auch den
> Registeradressraum einfach durchnummerieren?

Weil die Register früher grundverschieden waren (an vielen Stellen sind
sich das ja immernoch). Mit x86_64 hätte man die Schreibweise aber
endlich mal ändern können. Beachte aber, dass bei "Deiner" Schreibweise
der Registerraum auch nicht konsequenz durchnummeriert wird.

> Warum benutzt man
> so viele Namen (eax,ax,ah,al,ebx,bx,bh,bl,ecx,cx,ch,cl,edx,dx,dh,dl,
> ebp,bp,esi,si,edi,di,esp,sp) anstatt einfach r0-r7 zu verwenden.
> Glücklicherweise hat AMD die 64 Bit Erweiterung spezifiziert,
> denn sonst würden wir vermutlich nochmals jede Menge Namen für
> die restlichen Register haben.

Leider waren sie dabei nicht konsequent. Gerade bei Macros für
Kryptocode nervt das. Kann man sich ja dann mit Assemblermacros
umdefinieren.

> Was bitte hat die Operandengröße (8, 16, 32 Bit) bei den Operanden
> zu suchen?

Warum nicht? Man operiert ja durchaus mit Teilregistern.

> Eine 8 und eine 32 Bit Addition haben nun mal einen
> unterschiedlichen Opcode, die Addressangabe unterscheidet sich dagegen
> nicht. Es ist also völlig unlogisch zu schreiben:
>
> inc byte ptr [adresse]
>
> logisch ist:
>
> inc.b adresse

Man benutzt gerade einen Assembler, damit der einem Arbeit abnimmt.

Unterscheidest Du zwischen:

83 c0 01 │ add eax,1
05 01 00 00 00 │ add eax,1
81 c0 01 00 00 00 │ add eax,1

Ich gehe davon aus, dass das der Assembler das für mich übernimmt.

> Genau so unlogsch ist die unterschiedlich Indirektionsstufe im
> Speicher- und im Registeradressraum.
>
> Wenn ich die Zahl 5 in das Register eax schreiben will, kann ich
> entweder "mov (eax),5" oder "move eax,#5" (oder wie bei GAS $5)
> schreiben, aber sicherlich nicht "mov eax,5".

Warum? Viel dümmer finde ich in dem Zusammenhang, dass nicht unbedingt
klar ist, ob eax (oder r0) ein Symbol oder ein Register ist.

> Und das läßt sich beliebig fortsetzen. Ich habe bisher überhaupt
> noch nichts gefunden was bei der Intel Syntax auch nur annähernd
> logisch ist. Und noch schlimmer wird es dann bei "High Level"
> Assembleren wie MASM bei dem es dann auch noch Dinge wie PROC,
> ENDPROC, ASSUME usw. gibt (von denen die CPU nun absolut keine
> Ahnung hat).

Die CPU hat auch keine Ahnung von "move.b #$3c,m0". Deswegen
benutzt/braucht man ja Assembler.

--
Gruß,
Sebastian

Dirk Wolfgang Glomp

unread,
Aug 1, 2006, 1:38:33 PM8/1/06
to
Sebastian Biallas schrieb:

> Herbert Kleebauer wrote:
>> @=$100
>>
>>00000000: 00000100: b4 3c move.b #$3c,m0
>
> Was sind denn das für krasse x86-Mnemonics? Ist ja noch eine Spur
> ekelhafter als der AT&T-Style.

Herbert hat zum Glück wieder jeweils den Opcode mit angegeben.

Dirk

Stefan Reuther

unread,
Aug 2, 2006, 12:45:38 PM8/2/06
to
Herbert Kleebauer wrote:
> Sebastian Biallas wrote:
>>Im Übringen mag die x86-Architektur zwar furchtbar sein, die
>>Intel-Syntax hat aber so ziemlich die lesbarsten Assembler-Mnemonics,
>>die ich kenne.
>
> Genau anders herum. Seit dem 386 ist die Architektur ganz brauchbar
> (war echt eine tolle Leistung was die Intel Leute aus dem 16 Bit x86
> gemacht haben) nur bei der Assemblersyntax dreht es jedem logisch
> Denkenden den Magen um.
>
> mov ebx,eax; mov ecx,ebx; mov edx,ecx;

"Lade ebx mit eax, lade ecx mit ebx, lade edx mit ecx".

Vorgänger von x86 ist nun mal der 8080 / Z80, mit "ld bc,hl" usw.
Außerdem hat fast jede Programmiersprache die Zuweisungen in der
Reihenfolge "ziel := quelle".

> Warum kann man nicht genau so wie den Speicheradressraum auch den
> Registeradressraum einfach durchnummerieren? Warum benutzt man
> so viele Namen (eax,ax,ah,al,ebx,bx,bh,bl,ecx,cx,ch,cl,edx,dx,dh,dl,
> ebp,bp,esi,si,edi,di,esp,sp) anstatt einfach r0-r7 zu verwenden.

Weil die Registernamen eine Bedeutung haben und keinesfalls gleichwertig
sind. ax = *A*kkumulator, bx = *B*asisregister (für Adressierung und
xlat), cx = *C*ount register, dx = *D*ata, si = Source Index, di =
Destination index usw.

(Ganz besonders wunderbar finde ich ja deine Syntax für cli / sti mit
'bclr' und 'bset'. Was interessiert mich die Bitposition von dem Ding im
Flagregister?)

> Was bitte hat die Operandengröße (8, 16, 32 Bit) bei den Operanden
> zu suchen? Eine 8 und eine 32 Bit Addition haben nun mal einen
> unterschiedlichen Opcode, die Addressangabe unterscheidet sich dagegen
> nicht. Es ist also völlig unlogisch zu schreiben:
>
> inc byte ptr [adresse]
>
> logisch ist:
>
> inc.b adresse

Zum einen kannst du in "höheren" Assemblern wie TASM oder MASM "inc
variablenname" schreiben (wozu die Operandengröße wiederholen, wenn man
dem Assembler schon gesagt hat, dass das ein Byte ist?).

Zum anderen drückt 'inc byte ptr [adresse]' sehr deutlich aus, dass auf
Speicher zugegriffen wird. Insbesondere in Fällen, wo adresse=ebx ist o.ä.

Ob man nun 'inc byte ptr' oder 'incb' oder meinetwegen 'inc.b' schreibt,
ist durchaus verhandelbar.

> Genau so unlogsch ist die unterschiedlich Indirektionsstufe im
> Speicher- und im Registeradressraum.
>
> Wenn ich die Zahl 5 in das Register eax schreiben will, kann ich
> entweder "mov (eax),5" oder

Das ist eindeutigst eine Indirektion.

> "move eax,#5" (oder wie bei GAS $5)
> schreiben, aber sicherlich nicht "mov eax,5".

Momentmal. Ich will die Zahl 5


5
in das Register eax

eax
schreiben. Der Befehl zum Schreiben lautet 'mov'. Alles zusammen also
mov eax,5
Perfekt logisch für mich.


Stefan

Heiko Nocon

unread,
Aug 2, 2006, 2:15:52 PM8/2/06
to
Stefan Reuther wrote:

>Momentmal. Ich will die Zahl 5
> 5
>in das Register eax
> eax
>schreiben. Der Befehl zum Schreiben lautet 'mov'. Alles zusammen also
> mov eax,5
>Perfekt logisch für mich.

Für mich nicht. Dieses konkrete Problem ist allerdings auch fast der
einzige Punkt, bei dem ich mit der Meinung von H.K. konform gehe. Die
Geschichte lea vs. mov zeigt, daß es hier tatsächlich einen
systemimmanenten logischen Konflikt gibt. Der andere Punkt, bei dem ich
seine Auffassung teile, ist die Notation der Operandenbreite. Es ist
einfach logischer, dies einheitlich beim Operator zu notieren. Damit
wird die Notation nämlich unabhängig von der Art der Operanden.

Seine Konventionen für die Registerbenamsung hingegen sind angesichts
der Tatsache sinnlos, daß die Register in der x86-Architektur eben
niemals universell austauschbar waren und es auch heute trotz aller
Fortschritte immer noch nicht sind.
Das waren sie allerdings auch bei seiner offensichtlichen
"Heimatarchitektur", den 68k nicht vollständig, was sich schon allein
durch die Unterscheidung von aX und dX dokumentiert. Darüber hinaus
waren nichtmal die Register einer Gruppe 100% austauschbar, a7 z.b.
spielte da durchaus auch eine Sonderrolle.
Und wenn ich mir andere Inkarnationen dieser Grundidee anschaue
(AVR-Assembler z.B) da könnte einem regelrecht schlecht werden, denn
auch hier gibt es massive Einschränkungen bei der Benutzung der
Register, die sich ihren Bezeichnungen nicht entnehmen läßt.
Insofern kann er sich seine gesamte diesbezügliche Argumentation also
getrost herzhaft in den Arsch schieben. Sinnvoll ist der Ansatz dann
(und nur dann!), wenn die Register tatsächlich ohne jede Einschränkung
frei austauschbar sind.

Seine Einlassungen bezüglich der Reihenfolge der Notation von Quelle und
Ziel sind gleich ganz für'n Garten. In den weitaus meisten synthetischen
Sprachen (das geht weit über die diversen Assemblersprachen hinaus)
werden Zuweisungsoperationen so notiert, daß das Ziel links und die
Quelle rechts steht.

Dirk Wolfgang Glomp

unread,
Aug 2, 2006, 10:15:30 PM8/2/06
to
Heiko Nocon schrieb:

> Seine Einlassungen bezüglich der Reihenfolge der Notation von Quelle und
> Ziel sind gleich ganz für'n Garten. In den weitaus meisten synthetischen
> Sprachen (das geht weit über die diversen Assemblersprachen hinaus)
> werden Zuweisungsoperationen so notiert, daß das Ziel links und die
> Quelle rechts steht.

Ist es beim AT-Syntax nicht umgekehrt?

Dirk

Stefan Reuther

unread,
Aug 3, 2006, 11:43:06 AM8/3/06
to
Heiko Nocon wrote:
> Stefan Reuther wrote:
>>Momentmal. Ich will die Zahl 5
>> 5
>>in das Register eax
>> eax
>>schreiben. Der Befehl zum Schreiben lautet 'mov'. Alles zusammen also
>> mov eax,5
>>Perfekt logisch für mich.
>
> Für mich nicht. Dieses konkrete Problem ist allerdings auch fast der
> einzige Punkt, bei dem ich mit der Meinung von H.K. konform gehe. Die
> Geschichte lea vs. mov zeigt, daß es hier tatsächlich einen
> systemimmanenten logischen Konflikt gibt.

Das dürfte einfach deswegen ein Problem sein, weil die wichtigsten
Assembler eben zwischen
foo dw ?
mov ax, foo
und
foo equ 5
mov ax, foo
keinen syntaktischen Unterschied machen; der Assembler also
Typinformationen mitführen muss. Der unterschiedliche Opcode ist aus dem
Befehl selbst nicht erkennbar.

Im Disassemblat (und, war das nicht auch bei nasm so?) stehen dann
Speicheroperanden wieder gut erkennbar in Klammern.


Stefan

Dirk Wolfgang Glomp

unread,
Aug 4, 2006, 1:11:59 AM8/4/06
to
Stefan Reuther schrieb:

> Im Disassemblat (und, war das nicht auch bei nasm so?) stehen dann
> Speicheroperanden wieder gut erkennbar in Klammern.

Ja NASM benötigt immer []-Klammer.

...

Bei MASM sind sie optional, wenn mit einem Register als
Ziel/Quelle der Speicherzugriff vollzogen wird.
Sonst muß mit BYTE/WORD/DWORD PTR die []-Klammer gesetzt werden,
um die Zugriffsart zu spezifizieren.

Benutzt man im ersten Fall keine Klammern, können beim Lesen des
Listings, Konstante mit Speicher-Referenzen leicht verwechselt werden.
Um dieses Problem abzumildern, werden von mir Konstante groß+klein,
Speicheradressen in reinen Großbuchstaben geschrieben,
oder besser immer die []-Klammer benutzt.

Dirk

0 new messages