그래서 몇 가지가 있습니다 여기에 대해 이야기 해. 한 번에 하나씩 커버 해 봅시다.
먼저 OS가 없거나 (예 : 나만의 OS 만들기) 또는 I/O 방식으로 실행되지 않는 MS-DOS와 같은 OS에서 실행 중이라고 가정합니다. Olaf가 올바르게 지적한 것처럼 in al, 0x60
은 최신 보호 모드 OS에서 작동하지 않습니다. 고전적인 PS/2 키보드를 제공하는 것으로 보이는 가상 머신이나 에뮬레이터에서 실행하지 않는 한 USB 키보드에서도 작동하지 않습니다.
둘째, 저는 32 비트 CPU에서 프로그래밍 중이라고 가정합니다. C ABI (응용 프로그램 바이너리 인터페이스)는 16 비트 CPU, 32 비트 CPU 및 64 비트 CPU에서 서로 다르므로 사용중인 CPU에 따라 코드가 다르게 읽혀집니다.
셋째, 포트 60h는 이상한 짐승이며, 제가 운전 기사를 작성한 이후로 오랜 시간이 걸렸습니다. 읽은 값은 많은 시간에 읽을 것으로 생각되는 값이 아니며 E0h 확장 코드가 있으며 Pause 키의 동작이 있습니다. 버그없는 키보드 드라이버를 작성하는 것은 보이는 것보다 훨씬 어렵습니다. 그러나이 질문에 대한 모든 것을 무시합시다.
그런데 OS가없고 32 비트 CPU이고 가장 기본적인 키 스트로크 만 있다고 가정 해 보겠습니다. 어떻게 키보드에서 C 함수로 데이터를 전달하겠습니까? 꽤 많이 했어.
in al, 0x60
movzx eax, al
push eax
call cFunction
왜이 부분이 맞습니까?
음, 첫번째 줄은 키보드로 8 비트 레지스터를로드합니다. 그리고는 8 비트 레지스터이므로 in
에 쓸 수 있기 때문에 al
이어야합니다.
32 비트 C ABI는 함수의 매개 변수가 역 호출 순서로 스택에 푸시 될 것으로 기대합니다. 그래서 C 함수를 호출하기 전에 그 앞에 push
명령이 있어야합니다. 그러나 32 비트 모드에서 모든 push
명령어는 32 비트 크기이므로 eax
, ebx
, esi
, edi
등을 누를 수 있습니다. al
을 직접 푸시 할 수 없습니다. 32 비트 모드에서 푸시 된 모든 항목은 4 바이트 경계에 정렬되어야하기 때문에 직접 스택 쓰기를 사용하여 기술적으로 정렬 할 수는 있습니다. 따라서 값이 먼저 8 비트에서 32 비트로 승격되며, movzx
이이를 훌륭하게 수행합니다.
그럴 가치가있는 다른 방법이 있습니다.당신은 in
전에 eax
을 취소 할 수 :
xor eax, eax
in al, 0x60
push eax
call cFunction
이 솔루션은 성능을 원래의 솔루션보다 조금 더 나쁘다; 부분 등록 스톨의 비용이 있습니다. 프로세서는 내부적으로 을 eax
의 일부로 유지하지 않고 별도의 레지스터로 유지합니다. 레지스터 크기가 다른 여러 개의 하위 피스를 함께 섞으려는 시도는 프로세서가 스누핑을 수행 할 수 있기 전에 수행해야합니다. push eax
여기에서 프로세서는 al
이 이전 명령에 의해 돌연변이가 발생하고 클럭 사이클이 빨리 al
의 비트를 eax
에 매시 했으므로 여전히 al
인 것처럼 보입니다. 실제로는 eax
의 일부였습니다.
그것은 당신이 고전적인 16 비트 모드 (8086, 또는 '286 보호 모드)에 있다면, 호출 순서가 약간 다른 것을 지적 가치가
:
in al, 0x60
movzx ax, al
push ax
call cFunction
이 경우, int
는 16 비트 크기이므로 16 비트로 모든 것을 정확합니다. 또한, 64 비트 모드로, 대신 rax
를 사용해야합니다 :
in al, 0x60
movzx rax, al
push rax
call cFunction
cFunction는 int
는 32 비트, 64 비트 모드 명령에서 스택 정렬 요구되는 컴파일되었을 수도 있지만있는 64 비트 값이 푸시됩니다. C 함수는 64 비트 값을 32 비트 값으로 올바르게 읽지 만 64 비트로만 푸시 할 수 있습니다.
그래서 당신은 그것을 가지고 있습니다. CPU 및 환경에 따라 포트 데이터를 사용자의 기능으로 가져 오기 위해 C ABI와 상호 작용하는 다양한 방법.
일반적으로 4 바이트를 푸시해야하기 때문에'axx' (어셈블러에서 허용되는 경우)를 원하지 않습니다.이 경우 C 함수는 4 바이트 부호없는 int를 기대합니다. 당신이 한 일은 옳았습니다. – Jester
최신 OS가 있거나 USB 키보드를 사용하는 경우 작동하지 않습니다. – Olaf
AL을 EAX로 확장하는 것이므로 RAX = EAX = AX = AL = scancode에 해당하는 가치가 있습니다. –