Diskussion:Assembler-Programmierung für x86-Prozessoren/ Das erste Assemblerprogramm

Seiteninhalte werden in anderen Sprachen nicht unterstützt.
Aus Wikibooks

Unterschied zwischen Com und Exe[Bearbeiten]

Ich bin ein ASM-Anfänger und ich verstehe nicht warum bei der EXE Version folgende Zeilen steht:

mov ax, data 
mov ds, ax

Und es wird auch nirgends erklärt.. Wird damit das Daten-Segment des Programms im DS gespeichert? Warum reicht nicht ein

mov ds, data

? --Anonym001 14:25, 27. Feb 2006 (UTC)

Auf dem Intelprozessor der x86-Familie ist DS, eines der Segmentregister. DS ist das Standard-Register, wenn ein Speicherinhalt angefordert wird. Bei einer EXE Datei wird das Datenregister nicht reloziert, da eine Exedatei über mehrere Datensegmente verfügen kann und der Compiler schlicht und ergreifend nicht in der Lage ist, das richtige Segment auszuwählen. Selbst beim Linken einer EXE-Datei können weitere Datensegement dazugelinkt werden. Damit muss der Programmierer die Voraussertungen für einen korrekten Datenzugriff schaffen. Das erledigen die ersten beiden Zeilen.

Das Problem mit der letzten Zeile ist, dass die FA Intel ihre Prozessorfamilie so speezifiziert hat, dass ein direktes beschreiben des DS mit einem Wert nicht möglich ist. Es ist stets der Umweg über ein Register oder über den sog. Stack zu nehmen, dazu müssen der Stackpointer (SP) und das Stack-Segmentregister (SS). korrekt initialisiert sein, dann geht auch, das hat den Vorteil, den Registerinhalt nicht zu zerstören. HTH. Vielleicht kannst Du den Text diesbezüglich erweitern.

 push data
 pop  ds

-- ThePacker 18:25, 27. Feb 2006 (UTC)

Physische Adresse[Bearbeiten]

Ich bin ebenfalls Anfänger und verstehe die Berechnung der physikalischen Adresse nicht. Wie komme ich auf 4F28?

Hmm das Ergebnis 4F28 scheint falsch zu sein. Korrekt wäre: 0x0CDC * 16 +0x0100 = 0xCDC0 + 0x0100 = 0xCEC0. -- ThePacker 15:10, 7. Aug 2006 (UTC)

Was soll man mit einem 64bit Windows 7 system tun?

Fehler beim Umwandeln in obj-Datei[Bearbeiten]

Ich habe den Code exakt so abgeschrieben, wie er dort steht, und zuletzt sogar einfach rauskopiert, aber nasm.exe gibt bei mir immer folgende Fehlermeldung aus --> error: symbol 'data' undefined. --84.141.222.236 15:55, 3. Sep 2006 (CEST)

Oh, tut mir Leid, mein Fehler. Ich habe immer noch die alten Argumente für nasm.exe verwendet, und nicht -fobj. --84.141.222.236 15:59, 3. Sep 2006 (CEST)


Schritt 3 : Analyse[Bearbeiten]

Unter Schritt 3 : Analyse steht "Physikalische Adresse = 0100 + 0CDC * 16 = 4F28". Müsste das Ergebnis nicht

   0100
+ 0CDC0
  0CEC0

sein??

Einfach mal weiter 2 Beiträge weiter oben schauen.. -- ThePacker 11:40, 12. Jan. 2007 (CET)[Beantworten]
ups... Nicht gesehen. sorry. Dann kann der Beitrag wieder gelöscht werden
Trotzdem Danke für deinen Vorschlag. Ich ändere das jetzt gleich. -- Klaus 19:06, 12. Jan. 2007 (CET)[Beantworten]

Hello World-Programm[Bearbeiten]

Es ist ja inzwischen fast üblich geworden ein Hello World-Programm in einer Einführung in eine Sprache zu entwickeln. Dem wollen wir natürlich folgen:

org 100h
start:
 mov dx,hello_world
 mov ah,09h
 int 21h
 mov ah,4Ch
 int 21h
section .data
 hello_world: db 'hello, world', 13, 10, '$'

Nachdem Sie das Programm übersetzt und ausgeführt haben starten Sie es mit dem Debugger:

-r
AX=0000  BX=0000  CX=001B  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0000
DS=0CDC  ES=0CDC  SS=0CDC  CS=0CDC  IP=0100   NV UP EI PL NZ NA PO NC
0CDC:0100 BA0C01        MOV     DX,010C
- q

Wie Sie erkennen können, hat der Assembler hello_world durch die Offsetadresse 010C ersetzt.


Vielleicht könnte man an dieser Stelle nochmals erklären, wie sich die Offsetadresse zusammensetzt, da ich momentan selbst nicht nachvollziehen kann, woher das kommen soll. Auch in der Vorseite (Prozessor) konnte ich das nicht erörtern. Zum Beispiel ist bei mir "MOV DX,110" zu sehen, was mich sehr verwirrt. Da ich mich nicht auskenne, kann ich die Änderung leider nicht selbst durchführen... -- Daniel 28. Aug. 2007, 14:30 (CEST)

Ich bin mir nun nicht mehr so sicher, ob es doch an meinem Verständnis liegt, oder nicht. Liegt die Lösung in den Absätzen drunter? Ein Problem ist, daß ich ganz andere Adressen in den Registern stehen habe, und das verwirrt. Mal abwarten, vielleicht kommt die Erleuchtung noch... -- Daniel 23:46, 28. Aug. 2007 (CEST)


Diese Adresse zusammen mit dem CS-Register entspricht der Stelle im Speicher, in der sich der Text befindet. Wir müssen diese der Betriebssystemfunktion 9h des Interrupts 21 übergeben, die dafür sorgt, dass der Text auf dem Bildschirm ausgegeben wird. Wie kommt der Assembler auf diese Adresse?

Da sich der Text am Ende des Programms befindet, ermittelt er die Größe des Programms: Der Opcode von mov dx,010C hat eine Größe von 4 Byte, der Opcode von mov ah,09 und mov ah, 4Ch jeweils 2 Byte der Opcode der Interruptaufrufe nochmals jeweils 2 Byte. Der Programmcode hat somit eine Größe von 12 Byte dezimal oder C Byte hexadezimal.


Hier liegt meiner Meinung nach ein Fehler vor. Der Befehl mov dx,010C hat nur eine Größe von 3 Byte und nicht 4 wie oben steht. Dadurch ergibt sich allerdings eine Differenz zwischen der Summe der Bytes bis zum string 'hello, world' (müsste eigentlich 11 Bytes also 010B sein) und dem Wert der ins Register DX geladen wird (010C). Ich hab dann mal manuell den Wert 010B in DX geladen und die Ausgabe mit dem ursprünglichen Programm verglichen.

Bei 010C: 'hello, world'

Bei 010B: ' hello, world'

Es wird also nur das Leerzeichen weggelassen. Die Frage ist, wo kommt das Leerzeichen überhaupt her?


Eine weitere Anweisung in diesem Programm ist die DB - Anweisung. Durch sie wird ein Byte Speicherplatz reserviert. Der NASM kennt darüber hinaus noch weitere Anweisungen, um Speicherplatz zu reservieren.


Lässt sich die Differenz vielleicht durch das 1 Byte erklären, das mit der DB-Anweisung reserviert wird?

Bin selber noch Anfänger was Assembler betrifft, deshalb meine Bitte:

Kann das mal ein Experte nachvollziehen und korrigieren? Hat mich jetzt doch ziemlich verwirrt der Fehler.

Hello World-Programm[Bearbeiten]

Du hast mein Posting gestern offenbar leicht misinterpretiert. Der Befehl mov dx,hello_world hat eine Länge von 3 Byte. Das hast du jetzt korrigiert. Aber der Befehl lautet (beim Debuggen) trotzdem: mov dx,010c

D.h. also, dass der string 'hello, world' 12 Byte (= C) nach Programmstart im Programmcode steht. Die Summe aller Befehle ergibt aber nur 11 Byte. Und genau hier liegt das Problem.

Ich hatte ja geschrieben, dass das evtl. an der db-Anweisung liegt, die 1 Byte Speicher reserviert. Genau weiß ich das aber nicht, bin ja selber noch Anfänger.

Es fällt jedoch auf, dass die Ausgabe mit Leerzeichen vor 'hello, world' erfolgt, wenn man im Programmcode den mov-Befehl in mov dx,10bh ändert. Damit wird ja die Adresse ins Register dx geladen, die genau 11 Byte (= B) nach Programmstart liegt.

Wenn man allerdings die Marke hello_world ins Register dx lädt, ist das genauso wie wenn ich im Programmcode schreibe: mov dx,10ch

In diesem Fall erfolgt die Ausgabe ohne das Leerzeichen vor 'hello, world'.

Den Grund dafür kenne ich allerdings nicht. Würde mich aber sehr interessieren, wo das Leerzeichen herkommt bzw. wie die Differenz von 1 Byte entsteht. Am besten mal selbst ausprobieren, einmal mit mov dx,10bh und einmal mit mov dx,10ch im Progammcode. Denke dann wird klar, was ich meine.

Es könnte an den Voreinstellungen des NASM liegen, dass die Speicherzuweisung immer an einer geraden Adresse beginnt. Ich kann das nicht testen, habe keinen NASM installiert. Füge mal ein oder zwei NOP ein und sieh mal, was passiert. -- Klaus 10:08, 22. Feb. 2007 (CET)[Beantworten]
Ja, du hast Recht. Es liegt tatsächlich an der Speicherausrichtung. Die erfolgt an Doppelwort-Grenzen, also 4-byteweise. Kannst Du das vielleicht noch in einem Satz im Text erwähnen, damit andere auch Bescheid wissen? Schreib aber statt 'mov dx,010bh' wieder 'mov dx,010ch' hin, das hat ja gestimmt. Es sollte eben nur hervorgehen, dass die Differenz von 1 Byte (C - B = 1) von der Doppelwort-Ausrichtung herrührt. Danke. -- Andi 16:21, 22. Feb. 2007

linux user[Bearbeiten]

ich habe assembler hier das erste mal wirklich verstanden(und ich habe schon 2 tuts gelesen). was mich allerdings sehr enttäuscht ist die reduzierung auf windows/msdos. ich nutze seit langer zeit GNU/Linux und würde auch hier gerne den ersten code assemblieren. ich habe auch schon nasm heruntergeladen (ja, den gibts auch für linux) und versucht den code damit in eine binärdatei umzuwandeln - erfolgslos. ich kann weder eine lauffähige executable erstellen, noch diese mit gdb debuggen, bzw. disassemblieren.

über eine ergänzung würde ich (und auch ganz sicher viele andere) mich sehr freuen.

mfG Neme

Das Buch ist leider verwaist. Wenn du es rausgekriegt hast, wie es mit Linux geht, dann schreib doch deine Erkenntnisse dazu! -- Klaus 08:53, 8. Jul. 2007 (CEST)[Beantworten]

Es gibt noch den Flatassembler, siehe http://flatassembler.net/download.php

Hello World EXE[Bearbeiten]

Folgende Ausgabe bekomme ich:

C:\Temp\asm\002_HE~1>debug HELLO_EX.exe
-r
AX=0000  BX=FFFF  CX=FE7F  DX=0000  SP=0000  BP=0000  SI=0000  DI=0000
DS=154B  ES=154B  SS=155B  CS=155B  IP=0000   NV UP EI PL NZ NA PO NC
155B:0000 B85D15        MOV     AX,155D
-t

AX=155D  BX=FFFF  CX=FE7F  DX=0000  SP=0000  BP=0000  SI=0000  DI=0000
DS=154B  ES=154B  SS=155B  CS=155B  IP=0003   NV UP EI PL NZ NA PO NC
155B:0003 8ED8          MOV     DS,AX
-t

AX=155D  BX=FFFF  CX=FE7F  DX=0000  SP=0000  BP=0000  SI=0000  DI=0000
DS=155D  ES=154B  SS=155B  CS=155B  IP=0005   NV UP EI PL NZ NA PO NC
155B:0005 BA0000        MOV     DX,0000
-quit

Bei mir kommt DS(155Dh)-CS(155Bh)=2 raus. Warum? Was ist bei mir anders? -- Daniel 28. Aug. 2007, 15:22 (CEST)

Ich kann dir nicht sagen, was anders ist. Das hängt vermutlich vom verwendeten Assembler, Linker oder dessen Voreinstellungen zusammen. Fakt ist: Das EXE-Programm ist 18d = 12h Byte lang. Weil die Anfangsadressen jedes Segments vom Linker üblicherweise auf Adressen gelegt werden, die durch 16d = 10h teilbar sind, ergibt das genau den von dir beobachteten Abstand von 2. Falls dein Programm funktioniert, ist der Buchtext falsch. Was meinst du dazu? -- Klaus 20:28, 28. Aug. 2007 (CEST)[Beantworten]
Das Programm funktioniert einwandfrei. Ich habe den NASM Assembler, und den hier empfohlenen ALINK Linker verwendet. Betriebssystem ist MS Windows XP Pro SP2. Leider kann ich das im Moment nicht noch einmal nachvollziehen, da ich daheim kein Windows habe. Werde es gleich nochmal unter Linux versuchen, und berichten. -- Daniel 22:56, 28. Aug. 2007 (CEST)
Da es bei dir funktioniert, ändere ich jetzt das Buch. -- Klaus 00:07, 29. Aug. 2007 (CEST)[Beantworten]
Habe noch den Text angepasst, hoffe dass die Änderung der Richtigkeit entspricht... -- Daniel 10:44, 29. Aug. 2007 (CEST)
Man benutze
nasm hello.asm -g -f elf
anstatt
nasm hello.asm -f elf
(zusätzlich -g (siehe nasm --help)) und bekomme Debuginformationen in das Programm geschrieben. Nun kann man mit
ld hello.o -o hello
gdb hello
den Debugger starten. Bei mir konnte ich mit einem "break 5" und anschließendem "run" das Programm bis zur fünften Zeile ausgeführen (und dann pausieren). Schrittweise geht es mit "stepi" weiter und ein "info registers" zwischen den Schritten liest die Register aus.
(gdb) list
1       section .text
2       global _start
3       _start:
4           mov ecx, hello
5           mov edx, length
6           mov ebx, 1      ; Dateinummer der Standard-Ausgabe
7           mov eax, 4      ; Funktionsnummer: Ausgabe
8           int 80h
9           mov ebx, 0
10          mov eax, 1      ; Funktionsnummer: Programm beenden
(gdb) break 4
Breakpoint 1 at 0x8048080: file hello.asm, line 4.
(gdb) break 5
Breakpoint 2 at 0x8048085: file hello.asm, line 5.
(gdb) run
Starting program: /home/spitfire/projects/assembler/002_hello_world/hello 

Breakpoint 2, _start () at hello.asm:5
5           mov edx, length
(gdb) info registers
eax            0x0      0
ecx            0x80490a4        134516900
edx            0x0      0
ebx            0x0      0
esp            0xbf9e6140       0xbf9e6140
ebp            0x0      0x0
esi            0x0      0
edi            0x0      0
eip            0x8048085        0x8048085 <_start+5>
eflags         0x200292 [ AF SF IF ID ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x0      0
(gdb) stepi
_start () at hello.asm:6
6           mov ebx, 1      ; Dateinummer der Standard-Ausgabe
(gdb) info registers
eax            0x0      0
ecx            0x80490a4        134516900
edx            0xd      13
ebx            0x0      0
esp            0xbf9e6140       0xbf9e6140
ebp            0x0      0x0
esi            0x0      0
edi            0x0      0
eip            0x804808a        0x804808a <_start+10>
eflags         0x200292 [ AF SF IF ID ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x0      0
(gdb) stepi
_start () at hello.asm:7
7           mov eax, 4      ; Funktionsnummer: Ausgabe
(gdb) info registers
eax            0x0      0
ecx            0x80490a4        134516900
edx            0xd      13
ebx            0x1      1
esp            0xbf9e6140       0xbf9e6140
ebp            0x0      0x0
esi            0x0      0
edi            0x0      0
eip            0x804808f        0x804808f <_start+15>
eflags         0x200292 [ AF SF IF ID ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x0      0
(gdb) stepi
_start () at hello.asm:8
8           int 80h
(gdb) info registers
eax            0x4      4
ecx            0x80490a4        134516900
edx            0xd      13
ebx            0x1      1
esp            0xbf9e6140       0xbf9e6140
ebp            0x0      0x0
esi            0x0      0
edi            0x0      0
eip            0x8048094        0x8048094 <_start+20>
eflags         0x200292 [ AF SF IF ID ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x0      0
(gdb) stepi
Hello World!
Leider bin ich momentan mit der Ausgabe der Register überfordert. Werde mich morgen selbst nochmal hinsetzen, oder du findest gleich heraus, was nun der Fehler ist. (Programm oder Text) Eventuell wäre ja auch eine Erweiterung der Linux Sektion sinnvoll? BTW: Falls meine Eingaben hier nicht den Regeln entsprechen, sei so gut und entferne sie. Ich kenne mich nicht wirklich mit Wikipedia/WikiBooks aus... -- Daniel 00:10, 29. Aug. 2007 (CEST)
Du kennst dich nicht mit Wikibooks aus? Macht nichts, der Inhalt ist stets wichtiger als die Form, und die Diskussionsseiten sind für Diskussionen da. Und: Ich beschäftige mich wirklich nicht mit Linux, und der ursprüngliche Autor des Buches ist fort... Vielleicht kriegen wir es trotzdem hin. -- Klaus 00:24, 29. Aug. 2007 (CEST)[Beantworten]
Das Programm unter Linux ist zu anders, als das EXE Programm. Ich kann das somit nicht nachvollziehen. Aber: wenn ich soweit bin, werde ich versuchen das sonst sehr gute Buch mit ein paar Tips zu Linux spicken... -- Daniel 09:54, 29. Aug. 2007 (CEST)

Fehler beim Download des Assemblers[Bearbeiten]

Ich habe ein Problem. Ich kann den Assembler, den ich downloaden soll nicht finden. Wenn ich auf den Link klicke sehe ich nur eine lange Liste mit Versionen. Wenn ich eine davon Downloade, bekomme ich eine ganz tolle Hilfedatei, die keine Verbindung zum Internet aufbauen kann und deshalb nicht mal funktioniert. Kamm mir jemand sagen, wo genau ich das downloaden kann?

Wenn du Windows hast, geh mal auf diese Seite. :) -- heuler06 12:07, 2. Mai 2008 (CEST)[Beantworten]

Zum Teil unverständlich[Bearbeiten]

Für mich als Anfänger im Bereich Assembler ist diese Einführung doch etwas unverständlich. So wurden zwar die Register der 8086/8088-CPU erklärt, jedoch hat man erst danach erfahren warum man das brauch - Ich persönlich hasse so etwas.

Warum gibt es überhaupt verschiedene Register oder sind das nur Konventionen und man kann mit dem CX-Register rechnen und das AX-Register für Schleifen nutzen. mfg Nozdrum

Mehr zu den Registern findest du hier. Warum das mit den Registern so und nicht anders ist, werde ich jetzt aufschreiben, sieh Morgen mal hier hin. -- Klaus 19:15, 25. Jun. 2008 (CEST)[Beantworten]

Problem mit alink[Bearbeiten]

Jetzt habe ich noch ein konkretes Problem für Exe-Datein soll ich die Befehle nutzen: nasm hworld.asm -fobj -o hworld.obj alink hworld.obj Wenn ich in der Kommandobox ( WinXP ) das eingebe erhalte ich beim 2. Befehl die Fehlermeldung: "Der Befehl "alink" ist entweder falsch geschrieben oder konnte nicht gefunden werden." mfg Nozdrum

Wechsle mal in das Verzeichnis, in dem sich die Programme nasm und alink befinden. Wenn das nicht hilft, erläutere dein Problem genau. -- Klaus 19:15, 25. Jun. 2008 (CEST)[Beantworten]
Ahh alink ist schon wieder ein Programm. Liegt aber nicht in der zip-Datei die man sich herunterladen soll, mal schaun ob ich es finde. Danke für die Antwort. mfg Nozdrum

debug firstp.com unter Vista[Bearbeiten]

Bis zu disem Punkt funktioniert alles einwandfrei. Bei "debug firstp.com" ist dann nur noch schwarz in der Konsole zu sehen... Was muss man unter Vista anders machen? mfg ika

16 und 32 bit Register[Bearbeiten]

Ich war etwas verwundert, warum im DOS-Beispiel z.B. das Register AX und bei Linux EAX benutzt werden. Dass dies die entsprechenden 32 bit Register sind sollte vielleicht irgendwo stehen, oder im Artikel zum Prozessor benannt werden. Dazu könnte man vielleicht ne Grafik oder Tabelle machen wie diese hier: http://www.cs.virginia.edu/~evans/cs216/guides/x86-registers.png (achtung, vermutlich nicht frei).--85.179.23.38 12:30, 5. Aug. 2008 (CEST) .. hab grad gesehen, dass es ja schon als Anmerkung da steht[Beantworten]


erste EXE (Speicherplatz reservieren)[Bearbeiten]

Ich (blutiger Anfänger) hab mich gefragt, wie genau die verschiedenen Breiten bei der Speicherreservierung zustande kommen. Eine kleine Erklärung wäre vielleicht sehr hilfreich. Grüße Oruborus 04:41, 26. Jan. 2009 (CET)[Beantworten]