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 비트)로 인코딩되었으므로 eax
을 al
으로 변경하여 한 번에 한 바이트 만 가져오고 비교해야합니다. 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 바이트는 이전 값으로 남게됩니다 (예 : 공백 문자 읽기). eax
을 12345678
으로 설정하면 eax
의 값이 12345620
(ASCII의 경우 ' ' == 0x20
)으로 변경됩니다.
메모리보기를 사용하여 메모리의 특정 주소의 내용을 확인할 수도 있습니다. 예를 들어 cmp
을 cmp [esi+ecx],eax
으로 변경하고 해당 주소를 메모리보기에서 확인하면 두 번째 마지막 문자가 아니라 마지막 문자에서 두 번째 반복을 다시 가리킨다는 것을 알 수 있습니다.
디버거를 체크인 할 수 있습니다. 때로는 지루한 경우가 있습니다. 그런 다음에 자주 물어 보거나 소스 코드에 대해 생각하는 것보다 쉽습니다. 특히 오랜 시간 동안 붙어있는 경우 더욱 그렇습니다.
마지막으로 ... 왜 등록합니까? 컴퓨터 메모리는 별도의 칩이기 때문입니다. 그리고 무결 한 것처럼 보일 수도 있지만, mov al,[presetWord]
과 같은 명령어는 CPU 칩이 메모리 칩이 메모리 내용을 읽고 버스 와이어를 통해 CPU 칩으로 전송하는 동안 CPU 칩이 실제로 기다리는 동안 수백 개의 CPU 사이클을 실제로 멈출 수 있습니다. al
및 ecx
은 CPU 내부에 직접 존재하지만 CPU가 필요할 때 동일한 주기로 액세스 할 수 있습니다.
계산에 자주 사용하는 경우 값을 레지스터에 저장하고 메모리가 느려지 지 않도록 할 수 있습니다 (메모리 내용이 L0/1/2/3 캐시로 캐시 된 후에도 "수백 "사이클의 합리적인 금액, 때로는 캐시 CPU 칩에 직접 0 사이클). 하지만 예측 가능한 패턴으로 메모리에 액세스하기를 원하기 때문에 (캐쉬는 미리 읽을 수 있습니다) 합리적인 양으로 (캐시는 일반적으로 레벨에 따라 16-32B 크기에서 최대 4-8k 크기와 같이 작동합니다). 16 개의 서로 다른 8k 메모리 페이지와 같은 몇 가지 명령어로 액세스하는 경우 사용 가능한 캐시 라인이 부족할 수 있으며 실제 메모리 읽기를 기다리는 풀 스톨을 특징으로하는 액세스가 하나 이상있을 수 있습니다.
'ecx'를 포인터로 사용했지만 대신에 길이를로드했습니다. 또한 1 대신에 4 바이트 씩 처리합니다. 'mov al, [esi]; 대신에 cmp [presetWord + ecx], al. – Jester
'ECX'를 * 문자 수 *로 설정하면 메모리에 대한 포인터로 사용됩니다. 그것은 합리적인 어떤 것도 가리 키지 않으므로 물론 추락 할 것입니다. 'ECX'를 설정하여 길이가 아닌 길이를 + offset으로 설정해야합니다. –
@Jester 그래서 그것을 사용해서, 나는 여전히'mov ecx, OFFSET presetWord + SIZEOF presetWord - 1'을해야 할 것인가? –