Register verändern, ohne vorher zu retten
-
Hallo,
welche Register darf man im Assembler-Programm unter Linux verändern/verbiegen, ohne sie vorher auf dem Stack (oder woanders) zu retten?
Ich benutze den 2.6.xx Kernel. Rechner ist mit der Intel-i386 kompatiblen CPU.
Ich habe irgendwo gelesen, die Register eax, ecx und edx, fs, gs? Finde die Quelle aber nicht mehr... Wie sieht es mit dem Flag-Register aus? Mit den Segment-Registern?
-
soviel ich weiss kannst dus mit allen arbeiten ohne zu retten, du musst auch nicht ebp, esp etc. retten... schliesslich ist es dein Problem, wenn er dann "tot" ist.
-
Ich möchte aber gerne, dass mein Programm oder meine Funktion normal beendet wird, ohne "illegale Speicherzugriff"-Fehlermeldungen u.ä.
-
ein illegaler Speicherzugriff kommt nur dann, wenn du zB noch andere Sprachen in dein Programm einbettest die erwarten, dass man Register speichert. Dem Kernel ist es nämlich ziemlich wurscht ansonsten, welche Register wie belegt sind.
btw. die Segmentregister _kannst_ du garnicht verändern
-
zur Zeit rufe ich bloß eine Funktion der stdlib auf: die printf Funktion
Beim Beschreiben der Segment-Register kommt bei mir die "Speicherzugriffsfehler"-Fehlermeldung. Versucht habe ich so:movw %ax, %gs # hier auch %ds, %es, %fs
Danach gleich Speicherzugriffsfehler... also anscheinend darf man die Register nicht beschreiben.
Register edi scheint gleich nach dem Start des Programm die Adresse des Einsprungpunkts des Programms zu enthalten. Ich dachte, vielleicht hat das seinen Sinn und das Register sollte man nicht benutzen?
-
movw %ax, %gs # hier auch %ds, %es, %fs
ist doch AT&T, oder?
Dann versuchst du hier gs mit ax zu laden?? Was soll das für einen Sinn haben. Müsst das nicht 'ne Tripple-Fault geben!?Greetz, Swordfish
-
ja, ich habe versucht gs mit ax zu laden, aber nur so, probeweise, ob das sinnvoll ist oder nicht, sei zunächst dahingestellt. In jedem Fall wird das Programm abgebrochen und als einzige Ausgabe bekomme in meiner Konsole "Speicherzugriffsfehler".
Was ist ein Tripple-Fault?
-
Das ist eine spezielle Ausnahme des 80x86 im Protected Mode. Kann aber sein, das das OS diese Abfängt und "nur" eine Speicherzugriffsverletzung schmeißt. Ließ dazu ein Tutorial deines Vertrauens zum Protected Mode.
Greetz, Swordfish
PS: lass es, gs usw. lieber in Ruhe.
-
Wie sieht es unter Linux mit anderen allgemeinen Registern aus (abgesehen von sp, bp), die man nicht benutzen sollte bzw. vorher retten und nach der Benutzung wiederherstellen?
-
Du kannst alle Allzweckregister so verwenden wie du möchtest.
Das sind AX,BX,CX,DX,DI,SI,BP und SP , bzw. ihre 64 oder 32 bit Varianten z.b. RAX für 64bit, EAX für 32bit usw... R8 bis R15 sind die zusätzlichen Allzweckregister der 64bit CPU's. R8 wäre also 64bit breit, R8D 32bit, R8W 16bit und R8B 8bit...
Wenn du nicht mit den Interrupt Funktionen des Kernel arbeiten möchtest und lieber die libc / glibc Funktionen nutzen möchtest ( printf, scanf etc ), gibt es ein paar Dinge die du beachten mußt. Stichwort "Calling Conventions"
http://en.wikipedia.org/wiki/Calling_convention
32Bit Beispiel:
BITS 32 ; Unser Linux ist ein 32bit Betriebssystem und wir wollen 32bit ; Programme, wer hätte das gedacht *g global main ; die Funtktion Main ist der PEP, Programm Entry Point extern printf ; printf muss sich der Linker irgendwo anders suchen und ; er wird sie beim linken in der libc finden. section .data USE32 ; unsere data section, mit globalen variablen mytext: db "Hello World", 0xA, 0x00 ; Der Text den wir ausgeben möchten segment .code USE32 ; der eigendliche ASM code, natürlich auch 32bit allignment main: mov eax, mytext ; Laden der Adresse von "mytext" in ein beliebiges ; Allzeckregister. ; Aufruf von sprintf, welches die Calling Convention cdecl erwartet push eax ; Funktions Parameter werden in umgekehrter Reihenfolge ; auf den stack gelegt. call printf ; EIP landet auf dem stack und EIP wird mit der adresse ; von printf belegt. add esp, 0x04 ; cdecl besagt, das die aufrufende Funktion, die ; Parameter wieder vom stack entfernen muss. Dazu ; Zählen wir den Stackpointer einfach hoch... ; ( x86er Stacks wachsen nach unten ,) mov eax,0x0 ; Fertig, nun sagen wir dem OS noch das alles OK ist ret ; und beenden somit unser Programm
Compilieren kann man das ganze mit "nasm -f elf [FILENAME]" und linken mit gcc [FILENAME].o
Ich würde ohnehin zu nasm oder yasm raten. Die Dokumentation ist gut und imho ist die Intel Syntax besser lesbar als AT&T , wobei es sicherlich nicht schaden kann auch letzters zu kennen, denn GDB und co neigen dazu AT&T zu verwenden ,)
-
vielen Dank!
-
Hallo,
ich habe neulich versucht, folgenden Code zum Laufen zu bringen:str: .asciz "index = %i\n" movl $100, %ecx 0: pushl %ecx pushl $str call printf addl $8, %esp decl %ecx jnz 0b
und es geht nicht. Mit Hilfe einiger Debug-Ausgaben sieht es so aus, dass die Funktion printf den Inhalt des Registers %ecx verändert, ohne den Inhalt wiederherzustellen... Wenn man weiss, welche Register von der aufgerufenen Funktion verändert werden, ist das eigentlich nicht schlimm. Aber wie kann ich genau wissen, welche Register von der Funktion verändert werden? (ich meine jetzt also ohne den Quellcode der betroffenen Funktion zu studieren