2016-08-08 51 views
0

Ich versuche, ein Programm in Assembly, das zwei Zeichenfolgen überprüft.Assembly x86: Vergleichen von Zeichenfolgen funktioniert nicht

section .data 
str1 db 'mystring' 
str2 db 'mystring' 

output db 'cmp went fine' 
len equ $-output 

section .text 
global main 

main: 
    mov ecx, str1 
    cmp ecx, str2 
    je ifBody0 
    int 80h 

    mov eax, 1 
    mov ebx, 0 
    int 80h 

ifBody0: 
    mov eax, 4 
    mov ebx, 1 
    mov ecx, output 
    mov edx, outputlen 
    int 80h 

Das Seltsame ist, dass, wenn ich den bedingten Sprung nennen: je [label], funktioniert es nicht. Aber wenn ich je zu jne ändere, funktioniert es. Ich würde gerne wissen, was ich hier falsch mache.

str1 db 'mystring' 
     mov ecx,str1 

Nach dem Kompilieren dieses mit Assembler, die rohen Bytes von Maschinencode sieht zum Beispiel wie folgt aus (dieser Inhalt geworden von:

Vielen Dank im Voraus, Daan

+2

Gibt es einen Grund, warum Sie die Adressen von separaten Stringliterale vergleichen? – EOF

+0

@EOF Was meinst du genau? Ich bin neu in der Montage. Ich möchte die Strings vergleichen. –

+1

Kennen Sie zufällig C? Wenn dies der Fall ist, ist dies der gleiche Fehler wie beim Vergleich von C-Strings mit 'ptr1 == ptr2' anstelle von' strcmp (ptr1, ptr2) '. – EOF

Antwort

4

Zum Vergleichen von Strings in x86-Assembly gibt es einen speziellen OpCode namens CMPS(Compare Strings). In Ihrem Fall ist der relevante OpCode CMPSB. Sie verwenden es, indem Sie ESI auf die Quellzeichenfolge und EDI auf die Zielzeichenfolge festlegen. Die Länge der Gleichheitsprüfung (vorzugsweise die längste Zeichenfolge) wird in ECX festgelegt. Vorsicht vor Überläufen!.

So könnte Ihr Code wie folgt aussehen:

section .data 
str1 db 'mystring',0 
str1len equ $-str1 
str2 db 'mystring',0 

output db 'cmp went fine',0x0a,0 
outputlen equ $-output 
output2 db 'cmp went wrong',0x0a,0 
output2len equ $-output2 

section .text 
global main 

main: 
    lea esi, [str1] 
    lea edi, [str2] 
    mov ecx, str1len ; selects the length of the first string as maximum for comparison 
    rep cmpsb   ; comparison of ECX number of bytes 
    mov eax, 4  ; does not modify flags 
    mov ebx, 1  ; does not modify flags 
    jne ifWrong  ; checks ZERO flag 

ifRight:    ; the two strings do match 
    mov ecx, output 
    mov edx, outputlen 
    int 80h 
    jmp exit 
ifWrong:    ; the two strings don't match 
    mov ecx, output2 
    mov edx, output2len 
    int 80h 
exit:     ; sane shutdown 
    mov eax, 1 
    mov ebx, 0 
    int 80h 
+0

Danke, für Ihre Antwort –

+0

Vergessen Sie nicht, die Richtung Flagge angeben, wenn cmps verwenden – Tommylee2k

+0

@ Tommylee2k Was meinst du damit? –

2

die mit diesen beiden beginnen lassen Speicher nach den ausführbaren hinein geladen):

6D 79 73 74 72 69 6E 67 mystring 
B9 00 00 00 00   ¹.... 

die letzten 4 Nullen sind Adresse ‚m‘ Byte von ‚mystring‘, wie ich entschieden es wird an der Adresse 0 kompiliert. Die ersten 8 Bytes sind die Zeichenkettendaten (ASCII-codiert), B9 ist mov ecx,imm32 Befehlsopcode.

Sie können keine Zeichenfolge in ecx setzen, ecx ist 32 Bits breit (4 Bytes), während Zeichenfolge viele Bytes haben kann. Also mit ecx können Sie höchstens 4 Bytes von String abrufen, aber das würde mov ecx,DWORD [str1] erfordern, das würde den Wert 0x7473796D in ecx setzen (x86 ist Little Endian, also das erste Byte 6D ist der niedrigste Wert in DWORD (32b) Wert).

Aber mov ecx,str1 Lasten ecx mit str1 Symbol, die Adresse des ersten 'm' Byte (0x00000000).

Um zwei Strings zu vergleichen, laden Sie beide Adressen in einige Register, laden dann die Bytes von diesen Adressen und vergleichen sie nacheinander, bis Sie einen Unterschied (oder Ende der Zeichenkette) finden (es gibt schnellere Algorithmen, aber Sie sind komplexer und erfordern, dass Sie die Länge des vorausgehenden Strings kennen, während Byte-für-Byte-Vergleich problemlos mit C-ähnlichen, nullterminierten Strings arbeiten kann.

Über Länge der Schnur sprechen, sollten Sie irgendwie definieren. In C ist es üblich, null nach dem letzten Zeichen der Zeichenkette zu setzen (das wäre in diesem Beispiel B9 voraus), in C++ std::string ist die Struktur, die die Länge als Wert für direkten Abruf/Vergleich hält. Oder Sie können es in der Quelle fest codieren, wie Ihre outputlen.

Wenn Sie in Assembler programmieren, sollten Sie immer wissen, wie viele Bits Sie verarbeiten, und die richtige Registergröße wählen (oder den Wert erweitern) und die Speicherpuffergröße korrigieren, um den gewünschten Wert zu verarbeiten.

Mit Strings bedeutet das, dass Sie sich für die Codierung von Strings entscheiden müssen. ASCII ist 8 Bit pro Zeichen (1 Byte), UTF-8 hat eine variable Anzahl von Bytes pro Zeichen, eine frühe Version von UTF-16 (UCS-2) hatte 2 Byte pro Zeichen (wie Java, aber das aktuelle Utf-16 hat eine variable Länge), Utf-32 ist 4 Bytes pro Glyphe festgelegt. Also mit ASCII-codierte Zeichenfolge, um es zu holen ist das erste Zeichen zu tun (oder mov ecx,str1mov al,[ecx] ->al = 6Dh = 'm') Mit Utf-32, um zweites Zeichen zu holen, müssten Sie mov eax,DWORD [utf32str + 4] tun. Mit Utf-8 kann das einzelne Zeichen maximal 1 bis 6 Bytes haben, also müssen Sie das ziemlich komplex handhaben, um gültigen utf-8-Code zu erkennen und die korrekte Anzahl an Bytes zu lesen.Aber wenn Sie nur wissen wollen, ob zwei utf-8-Strings Bit-gleich sind, können Sie sie byteweise vergleichen, ohne Glyphen selbst zu behandeln.

Natürlich sollten Sie wissen, die Größe der Register und auf x86 die Art und Weise, wie Sie Unter-Teil einiger Register, dh. wie ax Teil (untere 16b) aus ganzen eax (32b), oder wie ah: al (hohe 8b: niedrige 8b) bilden zusammen ax.


Ich hoffe, dass Sie danach verstehen, dass Sie zwei Zeiger vergleichen hat (str1 vs str2), die immer ungleich sein wird, wie sie im Speicher zu anderen Byte zeigen. Anstatt den Inhalt im Speicher zu vergleichen (Strings).

+0

Vielen Dank für Ihre Antwort, dies mede es mehr clear –