2016-08-08 2 views
0

두 문자열을 검사하는 프로그램에서 어셈블리를 만들려고합니다. je [label], 그것은 작동하지 않습니다어셈블리 x86 : 문자열 비교가 작동하지 않습니다.

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 

이상한 것은 내가 조건부 점프를 호출 할 때이다. 그러나 jejne으로 변경하면 작동합니다. 내가 뭘 잘못하고 있는지 알고 싶습니다. 사전에

감사합니다, Daan

+2

있습니까? – EOF

+0

@ EOF 정확히 무엇을 의미합니까? 나는 새로운 어셈블리입니다. 나는 그 끈을 비교하고 싶다. –

+1

우연히 C를 아십니까? 그렇다면 이것은'strcmp (ptr1, ptr2) '대신'ptr1 == ptr2'에 의해 C- 문자열을 비교하는 것과 같은 오류입니다. – EOF

답변

4

x86 어셈블리의 문자열 비교를 위해 CMPS(Compare Strings)이라는 특수 OpCode가 있습니다. BYTE 문자열의 경우 관련 OpCode는 CMPSB입니다. 소스 문자열에 ESI을 설정하고 대상 문자열에 EDI을 설정하여 사용하십시오. 동일성 검사의 길이 (가장 긴 문자열이 바람직 함)는 ECX으로 설정됩니다. 오버플로에주의하십시오!.

그래서 코드는 다음과 같이 수 : 별도의 문자열 리터럴의 주소를 비교하는 이유는

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

고맙습니다, 대답은 –

+0

입니다. cmps를 사용할 때 방향 플래그를 지정하는 것을 잊지 마십시오 – Tommylee2k

+0

@ Tommylee2k 그게 무슨 뜻입니까? –

2

이의이 두 가지 시작하자 :

str1 db 'mystring' 
     mov ecx,str1 

을 어셈블러로이 컴파일 한 후, 기계 코드의 원시 바이트이의 내용이 될 것이다 (같은 예를 찾습니다 I 결정 같이

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

마지막 4 명 제로는 'mystring에'에서 'm'어드레스 바이트있다 : 메모리에 그것을 실행)을 로딩 한 후 주소 0에서 컴파일됩니다. 처음 8 바이트는 문자열 데이터 (ASCII 인코딩 됨)이고 B9mov ecx,imm32 명령어 opcode입니다.

ecx에 문자열을 넣을 수 없으며 ecx은 32 비트 (4 바이트)이고 문자열은 많은 바이트를 가질 수 있습니다. 따라서 ecx을 사용하면 문자열에서 최대 4 바이트를 가져올 수 있지만 mov ecx,DWORD [str1]이 필요하므로 0x7473796Decx에 넣어야합니다 (x86은 리틀 엔디안이므로 첫 번째 바이트 6D은 DWORD (32b) 값에서 가장 중요하지 않습니다).

그러나 mov ecx,str1로드 제 'm' 바이트 (0x00000000)의 주소 str1 기호로 ecx.

두 문자열을 비교하려면 두 주소를 일부 레지스터에로드 한 다음 해당 주소에서 바이트를로드하고 차이 (또는 문자열 끝)를 찾을 때까지 하나씩 비교하십시오 (더 빠른 알고리즘이 있지만 그들은 더 복잡하며 앞의 문자열의 길이를 알아야합니다. 바이트 단위의 바이트 비교는 C와 유사한 0 번째 종료 된 문자열로 쉽게 작업 할 수 있습니다.

문자열의 길이에 대해 말하면 어떻게 든 정의해야합니다. C에서 그것은 C++에서 B9보다 앞서 문자열의 마지막 문자 뒤에 0을 두는 것이 일반적입니다. std::string은 길이를 직접 가져 오기/비교를위한 값으로 유지하는 구조입니다. 또는 outputlen처럼 소스 코드를 하드 코드 할 수 있습니다.

어셈블러에서 프로그래밍 할 때 처리중인 비트 수를 알고 올바른 레지스터 크기를 선택하거나 값을 확장하고 메모리 버퍼 크기를 수정하여 원하는 값을 처리해야합니다.

문자열이란 문자열 인코딩을 결정해야한다는 의미입니다. ASCII는 문자 당 8 비트 (1 바이트), UTF-8에는 글리프 당 가변 바이트 수가 있고, UTF-16의 초기 버전 (UCS-2)은 글리프 당 2 바이트 (Java와 같이, 현재 Utf-16은 가변 길이입니다.), Utf-32는 글리프 당 4 바이트로 고정됩니다. 그래서 ASCII로 인코딩 된 문자열은 첫 번째 문자를 가져 오는 것이므로 mov al,BYTE [str1] (또는 mov ecx,str1mov al,[ecx] ->al = 6Dh = 'm') 두 번째 문자를 가져 오는 Utf-32를 사용하면 mov eax,DWORD [utf32str + 4]을 가져야합니다. Utf-8을 사용하면 단일 문자는 대부분 IIRC에서 1에서 6 바이트까지 가질 수 있으므로 매우 복잡한 방식으로이를 처리해야 올바른 utf-8 코드를 인식하고 올바른 바이트 수를 읽을 수 있습니다.그러나 두 개의 utf-8 문자열이 비트 평등한지 알고 싶다면 글리프 자체를 처리하지 않고 바이트 단위로 비교할 수 있습니다.

물론 레지스터 크기와 일부 레지스터의 하위 부분 주소 지정 방법을 알고 있어야합니다. eax (32b) 또는 ah : al (상위 8b : 하위 8b)이 모두 ax 인 양식에서 ax 부분 (아래 16b)과 같이 표시됩니다.


나는 그들이 메모리에 다른 바이트를 가리로 항상 동일하지 않은 것 두 개의 포인터 (str2str1)를 비교 않았다,이 후 이해를 바랍니다. 메모리 (문자열)의 내용을 비교하는 대신.

+0

답변 해 주셔서 감사합니다. 지우기 –

관련 문제