Hinweis: Das Forum wird geschlossen! Neue Registrierungen sind nicht mehr möglich!

 Zurück zu Pro-Linux   Foren-Übersicht   FAQ     Suchen    Mitgliederliste
[/] Ein paar Fragen zu Assembler

 
Neuen Beitrag schreiben   Auf Beitrag antworten    Pro-Linux Foren-Übersicht -> Programmieren - Allgemein
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
Lateralus
prolinux-forum-admin


Anmeldungsdatum: 05.05.2004
Beiträge: 1238

BeitragVerfasst am: 27. Jun 2005 11:18   Titel: [/] Ein paar Fragen zu Assembler

Mahlzeit

Ich habe mich dann doch einmal auf Assembler eingelassen. Ich möchte dabei ein kleines Programm schreiben, was von stdin liest und nach stdout schreibt, was in C so aussehen könnte:

cat.c
Code:
#include <stdio.h>

int main(){
        char c;
        while( (c=getc(stdin)) != EOF)
                putc(c, stdout);

        return 0;
}



Der erste Schritt war natürlich ein "hello world!" (nutze Intel-Syntax):

hello.asm
Code:
; from: Linux Assembly HOWTO

section .data                           ; section declaration

msg     db      "Hello, world!", 0xa    ; our dear string 0ax is '\n'
len     equ     $ - msg                 ; length of our dear string

section .text                           ; section declartion
                                        ; a program needs at least .text

                                        ; we must export the entry point
                                        ; to the ELF linker or loader. They
        global _start                   ; conventionally recognize start as
                                        ; their entry point. Use ld -e foo
                                        ; to override. the default

_start:

; write our string to stdout

; write(2) [ von mir eingefügt]
; #include <unistd.h>
;
;       ssize_t write(int fd, const void *buf, size_t count);
;               eax       ebx             ecx         edx


        mov     edx, len        ; third argument: message length
        mov     ecx, msg        ; second argument: pointer to message to write
        mov     ebx, 1          ; first argument: file handle (stdout == 1)
        mov     eax,4           ; system call number (sys_write) [ nachzulesen in /usr/include/asm/unistd.h]
        int     0x80            ; call kernel

; and exit

        mov     ebx, 0          ; first syscall argument: exit code
        mov     eax, 1          ; system call number (sys_exit)
        int     0x80            ; call kernel



Das ist soweit alles verständlich. Der nächste Schritt war für mich, anzuschauen, wie man Speicher reserviert. Dazu habe ich folgenden c-code kompiliert und disassemblet:

read.c
Code:
void main(){
        char buf[8];
        buf[7] = '\n';
}


Ausgabe von gdb, ein bisschen kommentiert:
Code:
(gdb) disassemble main
Dump of assembler code for function main:
0x08048354 <main+0>:    push   %ebp                     ; Inhalt von ebp auf Stack pushen
0x08048355 <main+1>:    mov    %esp,%ebp                ; esp (Stackpointer) nach ebp schreiben
0x08048357 <main+3>:    sub    $0x8,%esp                ;  0x8 von esp subtrahieren <- sind das unsere 8 Bytes?
0x0804835a <main+6>:    and    $0xfffffff0,%esp         ; logisches UND auf esp und 0xfffffff0 ausfuehren
                                                        ; Das heißt: die letzten zwei byte von esp auf Null setzen
                                                        ; Wohin wird das Ergebnis geschrieben? nach esp?
0x0804835d <main+9>:    mov    $0x0,%eax                ; 0x0 nach eax schreiben
0x08048362 <main+14>:   sub    %eax,%esp                ; esp von eax abziehen und in eax schreiben 
0x08048364 <main+16>:   movb   $0xa,0xffffffff(%ebp)    ; 0xa an die letzte Stelle von ebp schreiben
                                                        ; ( buf[7] = '\n' )
0x08048368 <main+20>:   leave                           ; ???
0x08048369 <main+21>:   ret                             ; return
0x0804836a <main+22>:   nop                             ; keine Operation
0x0804836b <main+23>:   nop
0x0804836c <main+24>:   nop
0x0804836d <main+25>:   nop
0x0804836e <main+26>:   nop
0x0804836f <main+27>:   nop
End of assembler dump.


Also den nop-Teil verstehe ich. Wink

So wie ich das sehe, beinhaltet esp die Addresse buf[7], zeigt also auf das Ende des Array. Das geht so ziemlich aus der Zeile <main+16> hervor. Ist das korrekt? Dann müsste man von dieser Addresse nur 7 Byte abziehen und würde auf buf[0] == buf zeigen. Das wäre dann 0xffffffc7(ebp).

Allerdings blicke ich im Gesamten irgendwie nicht durch. Ich habe zwar schon den Assembler-Code mit einem

Code:
gcc -S -masm=intel --static -o cat.S cat.c


erzeugt, aber da sehe ich noch weniger durch.


Die allgemeine Frage ist also: Wie realisiere ich, mir 1. Speicher zu verschaffen, 2. darauf per syscall zuzugreifen bzw. mir die richtige Addrese zu suchen und 3. das auch noch irgendwie mit einer Abfrage nach EOF in Verbindung zu bringen.


Desweiteren hätte ich die Frage, was ihr für eine Syntax bevorzugt - Intel oder AT&T - und natürlich aus welchen Gründen.


Gruß
Lateralus


Zuletzt bearbeitet von Lateralus am 28. Jun 2005 6:42, insgesamt 1-mal bearbeitet
 
Benutzer-Profile anzeigen Private Nachricht senden

klopskuchen
prolinux-forum-admin


Anmeldungsdatum: 26.06.2004
Beiträge: 1444

BeitragVerfasst am: 27. Jun 2005 17:23   Titel:

> Dann müsste man von dieser Addresse nur 7 Byte abziehen und würde auf buf[0] == buf zeigen.
In diesem Fall (char) ja. Ansonsten
Datentyp belegt n byte
Nullbyte (bzw. Terminierung) - array[n] = pointer auf erstes arrayelement

> Allerdings blicke ich im Gesamten irgendwie nicht durch. Ich habe zwar schon den Assembler-Code mit einem ...
> erzeugt, aber da sehe ich noch weniger durch.
Vieleicht sind nasm -arg && ld -arg freundlicher gegenüber Lernwilligen?

> Die allgemeine Frage ist also: Wie realisiere ich, mir 1. Speicher zu verschaffen, 2. darauf per syscall zuzugreifen
> bzw. mir die richtige Addrese zu suchen und 3. das auch noch irgendwie mit einer Abfrage nach EOF in Verbindung zu bringen.
Eine konkrete Antwort kann ich leider nicht geben, da sich mein Eifer nach groben Überblicken eines in den gdb gestopften Programmes erschöpft. Ohne selbst gesucht zu haben, guck mal unter den Kernelaufrufen:
http://unusedino.de/linuxassembly/syscall.html

> Desweiteren hätte ich die Frage, was ihr für eine Syntax bevorzugt - Intel oder AT&T - und natürlich aus welchen Gründen.
Verstehen kann man beide. Ich persönlich find die Intel-Syn. einfacher zu handhaben (weniger Tipperei, imo übersichtlicher-> Lesbarkeit). Die AT&T-Syntax hab ich mir allerdings als erstes näher angesehen: gcc-inline.
Übrigens schwirrt irgendwo im Netz ein Konverter Intel-> gas herum. Url entfallen. :-/

Soweit der Senf eines (bisweilen faulen) asm-noobs Wink

HTH, Klopskuchen
_________________
When all else fails, read the instructions .
 
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen

Lateralus
prolinux-forum-admin


Anmeldungsdatum: 05.05.2004
Beiträge: 1238

BeitragVerfasst am: 28. Jun 2005 6:40   Titel:

@klopskuchen: Danke für die Hilfe, allerdings habe ich die -arg-Option weder bei ld noch nasm gefunden... Ab welcher Version gibt's das und was genau macht es?

Also, das cat.asm ist fertig. Der Vergleich, ob EOF erreicht ist, orientiert sich daran, wieviel Bytes read(2) als gelesen zurückgibt. Den benötigten Puffer habe ich in die .data Section gelegt und 64 Byte groß gemacht - sonst muss man für jedes gelesene Byte in der Kern springen, was eine unglaubliche Verschwendung an Rechenzeit ist. Man kann den Speicher wohl auch irgendwie im Stack besorgen, indem man "einfach" Stack- und Basepointer manipuliert, aber das ging mir dann zu weit, will sagen: das verstand ich noch nicht so recht.

So sieht's dann aus:
Code:
section .data

; Unser Puffer
buf   times 64 db   'c'
len   equ      $ - buf

section .text

   global _start

_start:

; Linux Systemaufrufe lesen ihre Argumente aus den Registern
; Die Nummer des Systemaufrufs wird in eax uebergeben und ist in /usr/include/asm/unistd.h nachzulesen
; Der Kernsprung erfolgt ueber den Software-Interrupt 0x80

.read:
   ; ssize_t read(int fd, void *buf, size_t count)
   mov   eax, 0x3   ; #define __NR_read   3
   mov   ebx, 0x0   ; stdin
   mov ecx, buf      ; Addresse von buf
   mov   edx, len   ; Anzahl der zu lesenden Byte == len
   int   0x80      ; Kernel rufen
   
.check:
   cmp   eax, 0x0   ; 0 Byte gelesen - EOF
   je   .exit      ; jump if equal
   jmp   .write

.write:
   ; ssize_t write(int fd, const void *buf, size_t count);
   mov   edx, eax   ; Anzahl der gelesenen Bytes aus eax in edx schreiben
   mov   eax, 0x4   ; #define __NR_write   4
   mov   ebx, 0x1   ; stdout
   ; Addresse von buf liegt schon in ecx - nichts daran aendern
   int   0x80

   jmp   .read

.exit:
   mov   eax, 0x1   ; #define __NR_exit   1
   mov   ebx, 0x0   ; exit(0)
   int   0x80
 
Benutzer-Profile anzeigen Private Nachricht senden

hjb
Pro-Linux


Anmeldungsdatum: 15.08.1999
Beiträge: 3236
Wohnort: Bruchsal

BeitragVerfasst am: 28. Jun 2005 10:30   Titel:

Hi,

64-Byte-Puffer? Effizient wird es erst ab 4096 Bytes, eine größere Zweierpotenz ist zu empfehlen. Jedenfalls dann, wenn man direkt aus Dateien liest.

Speicherallokierung ist Sache der Anwendung. ob du eine malloc-Bibliothek verwendest oder alles selbst verwaltest, bleibt dir überlassen. Der einzige Syscall, der damit zu tun hat, ist brk, der die Obergrenze des virtuellen Speichers festlegt.

Gruß,
hjb
_________________
Pro-Linux - warum durch Fenster steigen, wenn es eine Tür gibt?
 
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen MSN Messenger

klopskuchen
prolinux-forum-admin


Anmeldungsdatum: 26.06.2004
Beiträge: 1444

BeitragVerfasst am: 28. Jun 2005 17:32   Titel:

> allerdings habe ich die -arg-Option weder bei ld noch nasm gefunden...
Missverständnis. Ich meinte die Verwendung von nasm und ld (mit argumenten) anstatt des gcc.

MfG, Klopskuchen
_________________
When all else fails, read the instructions .
 
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen

Beiträge vom vorherigen Thema anzeigen:   
     Pro-Linux Foren-Übersicht -> Programmieren - Allgemein Alle Zeiten sind GMT + 1 Stunde
Seite 1 von 1

 
Gehen Sie zu:  

Powered by phpBB © phpBB Group
pro_linux Theme © 2004 by Mandaxy