2016-12-19 1 views
0

어셈블리에서 특정 작업을 수행하는 방법을 스스로 가르쳐 왔습니다.문제 이해 레지스터 xx

지금 당장, 나는 검색을 시도하고 있습니다. 스택을 사용하거나 Irvine의 라이브러리를 사용하여 문자열을 비교할 수도 있지만 레지스터를 통해이를 수행하려고합니다.

레지스터를 사용할 때 문제는 다소 혼란 스럽습니다.

다음 컴파일,하지만 난 CMP 라인, 프로그램 중단에 도착하고 나에게이 메시지를 줄 때 :가 0xc0000005 : Project.exe에서 0x004033FC에서

처리되지 않은 예외 액세스 위치 0x0000000F를 읽고 위반.

내가 레지스터를 설정하는 방법과 관련이 있다고 가정하지만, 디버깅하는 동안 레지스터를 사용한다고해도 많은 도움이되지 않습니다.

도움을 주시면 감사하겠습니다.

INCLUDE Irvine32.inc 

.data 

enteredWord BYTE "Please enter the string to check: ", 0 
presetWord BYTE "Step on no pets", 0 

isAPalindrome BYTE "The word is a palindrome. ", 0 
isNotAPalindrome BYTE "The word is not a palindrome. ", 0 

.code 
main proc 
mov ecx, SIZEOF presetWord - 1 
mov esi,OFFSET presetWord 

checkWord: 
MOV eax,[esi] 
CMP [ecx],eax 
JNE NOTPALIN 

inc esi 
dec ecx 
loop checkWord 
mov edx, offset isAPalindrome 
call WriteString 
jmp _exit 
main endp 

NOTPALIN PROC 
mov edx, offset isNotAPalindrome 
call WriteString 
ret 
NOTPALIN endp 


_exit: 
exit 


end main 
+4

'ecx'를 포인터로 사용했지만 대신에 길이를로드했습니다. 또한 1 대신에 4 바이트 씩 처리합니다. 'mov al, [esi]; 대신에 cmp [presetWord + ecx], al. – Jester

+0

'ECX'를 * 문자 수 *로 설정하면 메모리에 대한 포인터로 사용됩니다. 그것은 합리적인 어떤 것도 가리 키지 않으므로 물론 추락 할 것입니다. 'ECX'를 설정하여 길이가 아닌 길이를 + offset으로 설정해야합니다. –

+0

@Jester 그래서 그것을 사용해서, 나는 여전히'mov ecx, OFFSET presetWord + SIZEOF presetWord - 1'을해야 할 것인가? –

답변

0

CPU 레지스터는 CPU 코어 내부에 직접 위치한 컴퓨터 메모리입니다. 컴퓨터 메모리 조각은 약간의 비트 (0/1)를 의미합니다. 64b x86 CPU의 경우 일반 레지스터는 이름이 rax, rcx, rdx, rbx, .. 인 64 비트 "와이드"입니다.

rcx의 하위 32b 부분입니다 (상위 32b 부분은 rcx을 사용하는 지침을 통해서만 특수한 이름으로 액세스 할 수 없습니다). 그리고 하위 16b 부분은 두 개의 8b 부분 ch (위)과 cl (아래)으로 구성된 cx을 통해 액세스 할 수 있습니다. 당신이 ecx를 사용으로

그래서, 당신은 0 또는 (헥사 0 .. 0xFFFFFFFF에서) 2 32 -1 0에서 부호없는 숫자를 해석, 또는 서명 된 수와 같은 수를 1로 32 개 비트를 설정할 수 있습니다 -2 to +2 -1 (0x80000000 .. 0x7FFFFFFF). 또는 원하는 방식으로 비트의 의미를 해석하고 코드를 작성할 수 있습니다.

코드에서 일부 CPU 레지스터의 비트 값을 해석하는 세 가지 일반적인 방법을 사용할 수 있습니다.

; EBX as memory address: 
mov ebx,OFFSET presetWord ; some address into memory (32b unsigned number) 
; ECX as numeric value ("unsigned long" in C++) 
mov ecx,SIZEOF presetWord - 1 ; 15 
; AL as ASCII character (extended 8 bit) 
mov al,[ebx]  ; also shows how memory is referenced by address 
; AL == 83 == 'S' => value of memory at address "presetWord" 
다행히 당신을 위해 불법 주소 15의 메모리를 참조하는 cmp [ecx],eax 수단을하고 당신의 예에서

, 그래서 충돌한다. 실수로 프로세스에 대한 법적 주소 (실수로 사용하려는 주소가 아님)를 사용하면 예기치 않은 결과가 발생해도 자동으로 진행되고 계속 진행됩니다.

presetWord+15 (문자열의 마지막 문자)에있는 메모리를 참조하는 것을 의미하는 cmp [esi+ecx],eax을 원했지만 첫 번째 반복에만 적용됩니다. 그런 다음 inc esi을 입력하면 presetWord+1 주소 (두 번째 문자)를 가리 킵니다.

그리고 문자가 ASCII 코드 (8 비트 당 8 비트)로 인코딩되었으므로 eaxal으로 변경하여 한 번에 한 바이트 만 가져오고 비교해야합니다. eax은 UTF-32 인코딩에서 작동합니다.


먼저 문자의 주소를 하나 개의 레지스터 ("R1")를로드 할 수 있습니다 회문을 확인, 하나 개의 레지스터 주소 ("R2") (!) 마지막 문자의 다음이 루프를 수행하려면 :

  • (R2 < = R1) 경우 -> 실제 (비교 중요한 문자)와 출구
  • 여기에 주소를 R1 < R2 (부호없는 번호로 주소를 확인) -> 지금 문자를 비교
  • 경우 (바이트 [r1]! = 바이트 [r2]) 종료 거짓
  • 012 3,516,
  • ++ R1, --r2는 ->에서 두 번째/마지막에서 두 번째 문자
  • 루프 시작을 가리 키도록 주소를 조정

당신이 할 수 있도록이, 'S' != 's'로, presetWord에 대해 "false"를 생성합니다 케이스 if (byte [r1]... 부분에 대소 문자를 구분하지 않아도되지만, 먼저이 기능을 사용하지 않는 것이 좋습니다.


디버깅 중에는 레지스터에있는 일부 클래스의 "클래스"를 인식 할 수 있어야합니다. 레지스터에 크기를로드하면 0000000F (15)과 같이 작은 숫자가 될 가능성이 큽니다. 주소는 8040506E과 같이 큰 숫자 일 가능성이 큽니다. 단일 문자로 사용될 때 ASCII 문자는 일반적으로 20 - 7F과 같은 결과를 가져 오지만, mov al,...을 수행하면 디버거에 전체 eax이 계속 표시되므로 상위 3 바이트는 이전 값으로 남게됩니다 (예 : 공백 문자 읽기). eax12345678으로 설정하면 eax의 값이 12345620 (ASCII의 경우 ' ' == 0x20)으로 변경됩니다.

메모리보기를 사용하여 메모리의 특정 주소의 내용을 확인할 수도 있습니다. 예를 들어 cmpcmp [esi+ecx],eax으로 변경하고 해당 주소를 메모리보기에서 확인하면 두 번째 마지막 문자가 아니라 마지막 문자에서 두 번째 반복을 다시 가리킨다는 것을 알 수 있습니다.

디버거를 체크인 할 수 있습니다. 때로는 지루한 경우가 있습니다. 그런 다음에 자주 물어 보거나 소스 코드에 대해 생각하는 것보다 쉽습니다. 특히 오랜 시간 동안 붙어있는 경우 더욱 그렇습니다.


마지막으로 ... 왜 등록합니까? 컴퓨터 메모리는 별도의 칩이기 때문입니다. 그리고 무결 한 것처럼 보일 수도 있지만, mov al,[presetWord]과 같은 명령어는 CPU 칩이 메모리 칩이 메모리 내용을 읽고 버스 와이어를 통해 CPU 칩으로 전송하는 동안 CPU 칩이 실제로 기다리는 동안 수백 개의 CPU 사이클을 실제로 멈출 수 있습니다. alecx은 CPU 내부에 직접 존재하지만 CPU가 필요할 때 동일한 주기로 액세스 할 수 있습니다.

계산에 자주 사용하는 경우 값을 레지스터에 저장하고 메모리가 느려지 지 않도록 할 수 있습니다 (메모리 내용이 L0/1/2/3 캐시로 캐시 된 후에도 "수백 "사이클의 합리적인 금액, 때로는 캐시 CPU 칩에 직접 0 사이클). 하지만 예측 가능한 패턴으로 메모리에 액세스하기를 원하기 때문에 (캐쉬는 미리 읽을 수 있습니다) 합리적인 양으로 (캐시는 일반적으로 레벨에 따라 16-32B 크기에서 최대 4-8k 크기와 같이 작동합니다). 16 개의 서로 다른 8k 메모리 페이지와 같은 몇 가지 명령어로 액세스하는 경우 사용 가능한 캐시 라인이 부족할 수 있으며 실제 메모리 읽기를 기다리는 풀 스톨을 특징으로하는 액세스가 하나 이상있을 수 있습니다.

+0

부수적으로 .. 어셈블리에는 변수의 "유형"또는 기타 항목이 없습니다. 이 코드는 그 비트에 의미/구조를 부여하는 코드입니다. 따라서 ASCII 문자가 8 비트 인 것처럼 작업하는 데이터의 크기를 항상 알고 있어야합니다. 그래서 당신은 단일 바이트만을 읽고 + -1로 포인터를 조정하는 코드를 작성합니다. 데이터가 16b 이상으로 작동한다면 단어를 읽고 포인터를 + -2로 조정하거나 'mov ax, [esi + ecx * 2]'와 같이 주소 지정에 * 2를 사용하는 것이 좋습니다. 따라서 8/16/32 비트가 의미하는 바를 이해하고 바이트/워드/워드 (word/word)는 무엇인지, C++로 일반적인 유형을 인코딩하는 방법 (영감으로)을 확인하십시오. – Ped7g

+0

이전 의견에서 썼 듯이 "banab"문자열을 테스트 중이지만 여전히 실패합니다. 또한, 업데이트 된 이후 내 코드는 다음과 같습니다. http://imgur.com/a/pUJYa –

+0

또한 크기와 관련하여 'mov ax, [esi + ecx * TYPE presetWord]'? –