Assembler-Code verstehen?

5 Antworten

https://i.stack.imgur.com/qGrzG.png

.text gehört zum Codesegment (RO).

global main ist ein globales Symbol, die Adresse von main: wird als Symbol main exportiert udn dient als Einsprungpunkt.

Der Rest ist entsprechend kommentiert.


RedDevil1982 
Beitragsersteller
 12.04.2023, 19:32

Danke! Allerdings versteh ich ehrlich gesagt hier nur Bahnhof. Kannst du mir ne gute Seite im Internet empfehlen, wo einem dieser Code für das HelloWorld Programm im Assembler verständlich erklärt wird. Danke!

0
KarlRanseierIII  12.04.2023, 20:35
@RedDevil1982

Nicht wirklich, da die Kommentare eigentlich schon sehr ausführlich sind.

Was Du da siehst ist nichts anderes als ein Syscall, also ein Systemaufruf an den Kernel, der eigentlich Aufruf ist das int80h, davor werden die Argumente festgelegt.

Letztlich steht da:

syscall(write, STDOUT, mymsg, mylen)
int80h (eax=4[write], ebx=1[STDOUT], ecx=mymsg, edx=mylen)

Bushmills145 hat Dir eine Quelle verlinkt in der die Syscalltabelle und die Register für die Argumente stehen.

0

Hi RedDevil1982

da müsstest du dich bitte ein bisschen frei machen von der Vorstellung, dass dieser Abschnitt was mit Java oder so zu tun hat. Natürlich mache der Assembler-Übersetzer daraus so etwas wie das, was in deinem Beispiel steht, aber das Prinzip ist doch etwas anders.

  • die "section ..." - Anweisungen unterteilen deinen Code bzw. das, was rauskommt in bestimmte Abschnitte - die braucht später der Linker. Im .text siehst du die ausführbaren Anweisungen, in .data stehen die festen Daten wie Strings, Zahlen usw. . Die Adressen der Strings (z. B.) setzt der Assembler ein und der Linker sorgt dafür, dass die Adressen bei der Ausführung gefunden werden. Das ist aber sehr rudimentär erklärt - da kommt auch noch der Ladevorgang durch das OS dazu etc.. Also Kurz: "Wo findet man den Programmcode bzw.. die Daten.
  • global main: eine globale deklaration (im Unterschied zu einer lokalen), wo (im Speicher) eine bestimmte Adresse zu finden ist. In diesem Fall ist das eben der Einsprungpunkt in das Programm, wo es gestartet wird. Das "public static void main(String[ ] args) " ist im Endeffekt das Ausgangs-Produkt, das hinterher in Assembler (nicht: Maschinensprache - die wäre binär) übersetzt wird.
  • mov eax, mov ebx: Damit werden die Register des Prozessors mit bestimmten Werten geladen (hier eben 4 und 1). Das dient als Parameter (vergleichbar mit den Parametern für eine Java-Prozedur oder Funktion) für die danach aufgerufene Prozedur. eben wie in "public static void main(String[ ] args) " das args...
  • die "4" ist sowas (sehr vereinfacht) wie die aufgerufene Hauptfunktion - sagen wir dazu mal "print"
  • die "1" ist der Deskriptor des Files, auf das geschrieben wird. In diesem Fall ist es eben der Deskriptor (das File) 1 und entspricht "stdout" also der Standardausgabe. "2" wäre "stderr" also der Fehlerkanal.
  • "move ecx, mymsg": da wird die Adresse des Strings, der ausgegeben wird, in das ecx-Register geladen - dort findet die Prozedur die Daten und in edx lädt man dann die auszugebende Länge.
  • danach erfolgt der Aufruf der Prozedur mit "int 80h" - das ist eine Prozedur, die entweder im Kernel oder in der Hardware definiert wird. Schreibt man das also in Java (seeehr rudimentär) so wäre das
  • int_80h (function_print, channel_1, meintext, dessenlänge) oder
  • int80h( 4, 1, mymsg, mylen).
  • Danach wird der int80h mit den Parametern 1 für "Programm verlassen" in eax und "0" für den Returncode 0 aufgerufen - das Programm ist aus, nachdem es irgendwas auf die Standardausgabe geschrieben hat.

Das ist hier auf GF nur schwer zu erklären. bitte besorg dir mal etwas Literatur über Assembler und denk dich da ein. Wenn du noch einen Anstoß brauchst, immer her damit.


RedDevil1982 
Beitragsersteller
 11.04.2023, 15:54

Wie gesagt, mich interessieren nur die Basic damit ich so einfache Programme verstehen kann. Kennst du eine gute Quelle wo diese gut erklärt werden.

0
norbertk62  11.04.2023, 16:08
@RedDevil1982

Weisst du, RedDevil1982 -da triffst du einen wirklich wunden Punkt.

Beschäftigt man sich mit den "normalen" Programmiersprachen (Java, Cpp, Pascal, VBA usw), dann denkt man, man hat es verstanden.

Du bist da aber unter die Oberfläche gestoßen - da muss man umdenken. Ich kenne das - bin Ausbilder.

  • leider kenne ich keine direkte Quelle. Ich kann nur Bücher über Assemblersprache empfehlen. Die gibt es als PDF auch als Download. Einfach googeln. Man kann ruhig auch mal ein Buch über 16bit Prozessoren "anlesen" - da ist etwas weniger Verwirrung drin.
  • um "reinzukommen": das ist haarig, weil es "anscheinend" der Logik des Programmierers widerspricht. Stimmt aber nicht !
  • Nur Stichpunkte:
  • Mal über die Turing-Maschine und die von von-Neumann ein bisschen lesen - da geht es darum, was einen Computer (egal, welche Art und welches OS) ausmacht.
  • Dann etwas über irgendwelche Assembler lesen. Ein bisschen eindenken: wo ist eigentlich der Unterschied zwischen 8 / 16 / 32 / 64 Bit-Prozessoren. Dabei sieht man die Architektur des Prozessors (welche Teilchen sind innendrin). Wie funktioniert das (Zyklen "Fetch - Decode - Execute - Store")
  • Dann: einen C / Cpp-Compiler nehmen (DevCpp) und ein Minimal-Programm schreiben ("Hallo Welt"). Das muss man aber so kompilieren lassen, dass man nicht das Programm rausbekommt, sondern den Assembler-Code (das ist ein Parameter - muss man suchen).
  • und dann wieder grübeln. Sorry - das ist nicht so leicht. Das ist auch bestimmt nicht in einer kurzen GF-Antwort zu beantworten. Da kannst du nur die Anregungen holen.
0
RedDevil1982 
Beitragsersteller
 11.04.2023, 16:12
@norbertk62

Ok, vielen Dank auf jeden Fall. Eine Frage hab ich zu dem Code noch:

Bei section . data in der letzten Zeile

mylen equ $-msg

Was soll das noch bedeuten?

mylen ist ja die Nachrichtlänge

equ ist warscheinlich der Name der Variablen

$-msg ???

0
norbertk62  11.04.2023, 16:25
@RedDevil1982

Oh - du hast den Trick gefunden. Ich muss mal ausholen

mymsg db 'Hello World!', 0xa

mylen equ $-mymsg

  • jedes Label (mylen, mymsg) ist nicht einfach ein Variablenname, sondern auch die Adresse im Speicher, die unter diesem Namen erreichbar ist
  • also ist mylen (dahinter kommt ja db also 'define byte') die Adresse des 'H' - eben dem ersten Buchstaben. Die Adresse von 'e' wäre also mymsg+1 (eben das nächste Zeichen).
  • das '$' steht für die aktuelle Adresse. Das ist aber in diesem Fall z. B. vom Typ Integer (Größe je nach Prozessortyp / Registerbreite). Also wäre '$'-1 (bei mylen) die Adresse von '!' - nämlich dem letzten Zeichen des vorangegangenen Strings
  • folgt ganz klar:
  • $ - mymsg heißt ausgeschrieben
  • (aktuelle Adresse) - (Adresse des Strings)
  • $ (aktuelle Adresse) - mymsg (Adresse des Strings) ergibt die Länge des Strings

Cool - oder ?

0
norbertk62  11.04.2023, 20:42
@RedDevil1982

equ bedeutet "=" und bezieht sich immer auf die Größe der Register (16, 32, 64 bit). Das ist die Adressierung.

1
RedDevil1982 
Beitragsersteller
 13.04.2023, 16:26
@norbertk62

Noch ne Frage zu dem Hello World Code:

Ist das fest(immer) so festgelegt, dass die Standard-Ausgabe sdout „immer“ über das Register ebx ablaufen muss,

dass die Adresse (Wert) der ausgeben werden soll immer in ecx stehen muss?

Das in eba die systemcall stehen müssen?

Oder ist das beliebig wählbar, welches Register ich dort wähle?

0
norbertk62  13.04.2023, 16:34
@RedDevil1982

Das ist definiert durch die Programmierung des syscall (bla, bla, ..). Der erwartet eben immer in den bestimmten Registern die entsprechenden Werte (sonst müsste er ja "raten", was er (z.b.) unter "4" verstehen soll.

Also - ja, das ist durch die Programmierung (des Kernels / der Firmware) festgelegt (und natürlich: stdin=0, stdout=1, stderr=2 und die ganzen anderen Systemkonstanten).

Es gibt natürlich eine genaue Doku darüber, welcher "int xxxh" mit welchen Parametern in den Registern aufzurufen ist und was er macht - aber die habe ich bisher noch nicht gebraucht - kann ich nicht sagen.

0

Section .text bezeichnet das Codesegment. "global main" bedeutet, dass das Symbol "main" auch ausserhalb des Objektes sichtbar ist für den Linker (und dort referenziert werden darf).

"4" in eax bedeutet, dass die Systemfunktion Nr. 4 aufgerufen wird, die eben sys_write entspricht.

"1" in ebx bedeutet, dass der File Descriptor, welcher der Funktion sys_write als Parameter via Register übergeben wird, dem Standard Output Filedescriptor entspricht. Auf Unix-basierten Systemen sind die File Deskriptoren mit den Nummern 0, 1 und 2 reserviert für stdin, stdout, und stderr.

mov ecx, mymsg: Der Offset (Speicheradresse) des ersten Bytes des Strings mymsg wird ins ecx Register geschrieben.

Section .data bezeichnet ein Datensegment.

mov eax, 4

setze eax auf den wert 4

usw.

MOV <target>,<source>

wobei source sowohl ein wert als auch ein register sein kann

mov eax, 4       # 4 gibt an, um welche Funktion vom System gefragt wird - in diesem Fall "Text ausgeben".
mov ebx, 1       # file handle besagt, wohin ausgegeben werden soll - Standard Ausgabe device hier.
move ecx, mymsg  # zeigt auf das erste Zeichen vom auszugebenden Text

Die sections besagen, welchem Grad von Schutz deren Inhalt im finalen Programm unterworfen sind bzw. unterworfen werden dürfen. Insbesondere, welche Daten verändert werden können, und wobei es sich nicht um ausführbaren Code handelt.

global ist ein Hinweis für den Linker, und dient der Kontrolle von Sichtbarkeit von Symbolen, wichtig beim Zusammenfügen von mehreren Programmteilen.


Woher ich das weiß:Berufserfahrung – hard meets soft

RedDevil1982 
Beitragsersteller
 11.04.2023, 18:45

Danke!

0
Bushmills145  11.04.2023, 16:02

Eine Übersicht über weitere syscalls kannst du z.B. hier finden:

https://gist.github.com/yamnikov-oleg/454f48c3c45b735631f2

0
RedDevil1982 
Beitragsersteller
 13.04.2023, 16:26
@Bushmills145

Noch ne Frage zu dem Hello World Code:

Ist das fest(immer) so festgelegt, dass die Standard-Ausgabe sdout „immer“ über das Register ebx ablaufen muss,

dass die Adresse (Wert) der ausgeben werden soll immer in ecx stehen muss?

Das in eba die systemcall stehen müssen?

Oder ist das beliebig wählbar, welches Register ich dort wähle?

0
Bushmills145  13.04.2023, 17:49
@RedDevil1982

Nein, das ist von Betriebssystem zu Betriebssystem, und von Prozessor zu Prozessor verschieden.

Die Vorgaben, die du jetzt verwendest, sind spezifisch für 32 bit Linux, welches unter einer CPU der i386 Familie läuft.

Andere CPU-Archtekturen kennen nicht mal ein ebx-Register,.

0