[Assembly Language] RDTSC 명령어 활용
Assembly 2023. 1. 11. 09:44 |Intel® 64 and IA-32 Architectures Software Developer’s Manual을 확인해 보자.
RDTSC—Read Time-Stamp Counter
Reads the current value of the processor’s time-stamp counter (a 64-bit MSR) into the EDX:EAX registers. The EDX register is loaded with the high-order 32 bits of the MSR and the EAX register is loaded with the low-order 32 bits. (On processors that support the Intel 64 architecture, the high-order 32 bits of each of RAX and RDX are cleared.) The processor monotonically increments the time-stamp counter MSR every clock cycle and resets it to 0 whenever the processor is reset.
RDTSC 인스트럭션은 프로세서의 time-stamp counter를 EDX:EAX 레지스터로 가져온다. EDX에는 상위 32비트가 저장되고 EAX에는 하위 32비트가 저장된다.
EDX, EAX에 저장되는 값을 확인해 보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
%include "io64.inc"
section .text
global CMAIN
CMAIN:
rdtsc
PRINT_STRING 'High-order 32 bits of Time Stamp Counter: '
PRINT_HEX 4, edx
NEWLINE
NEWLINE
PRINT_STRING 'Low-order 32 bits of Time Stamp Counter: '
PRINT_HEX 4, eax
NEWLINE
NEWLINE
PRINT_STRING 'Time Stamp Counter: '
shl rdx, 32
xor rdx, rax
PRINT_HEX 8, rdx
xor rax, rax
ret
|
EAX 레지스터에 저장된 값을 이용해 1~10까지의 랜덤 넘버를 추출해 보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
%include "io64.inc"
section .text
global CMAIN
CMAIN:
rdtsc
;eax에 저장되는 값을 사용한다.
PRINT_STRING 'Low-order 32 bits of Time Stamp Counter (dividend): '
PRINT_HEX 4, eax
NEWLINE
NEWLINE
;2byte 이상 나누기 연산시 div 는 dx, ax를 사용한다.
;나누어지는 값을 dx:ax에 나누어 삽입해야 하므로 edx를 0으로 만들고 eax의
;값 중 2바이트만 사용한다.
xor edx, edx
and eax, 0x0000ffff
PRINT_STRING 'DX: '
PRINT_HEX 2, dx
NEWLINE
PRINT_STRING 'AX: '
PRINT_HEX 2, ax
NEWLINE
NEWLINE
mov bx, 0xa ;나누는 수를 10으로 설정한다.
PRINT_STRING 'Divisor: '
PRINT_HEX 2, bx
NEWLINE
div bx ;bx(10)로 나눈다. 나머지는 0~9가 나온다.
PRINT_STRING 'Quotient: '
PRINT_HEX 2, ax ;몫은 ax에 저장된다.
NEWLINE
PRINT_STRING 'Remainder: '
inc dx
;나머지는 dx에 저장된다. 1을 더해서 범위를 1~10으로 맞춘다.
PRINT_HEX 2, dx
xor rax, rax
ret
|
그런데 실제로 여러번 해 보면 홀수만 나오는 것을 알 수 있다. 내 컴퓨터에서만 그러는건지는 모르겠지만 rdtsc 명령어가 (EAX 레지스터에)짝수만 반환하기 때문이다. (마지막에 1을 더하므로 결국 홀수가 된다)
EDX 레지스터의 값을 사용해 보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
%include "io64.inc"
section .text
global CMAIN
CMAIN:
rdtsc
;edx에 저장되는 값을 사용한다.
PRINT_STRING 'High-order 32 bits of Time Stamp Counter (dividend): '
PRINT_HEX 4, edx
NEWLINE
NEWLINE
;2byte 이상 나누기 연산시 div 는 dx, ax를 사용한다.
;나누어지는 값을 dx:ax에 나누어 삽입해야 하므로 edx의 값을 eax에 저장하고
;edx를 0으로 만든다. 그리고 eax의 값 중 2바이트만 사용한다.
mov eax, edx
xor edx, edx
and eax, 0x0000ffff
PRINT_STRING 'DX: '
PRINT_HEX 2, dx
NEWLINE
PRINT_STRING 'AX: '
PRINT_HEX 2, ax
NEWLINE
NEWLINE
mov bx, 0xa ;
PRINT_STRING 'Divisor: '
PRINT_HEX 2, bx
NEWLINE
div bx
PRINT_STRING 'Quotient: '
PRINT_HEX 2, ax
NEWLINE
PRINT_STRING 'Remainder: '
inc dx
PRINT_HEX 2, dx
xor rax, rax
ret
|
하지만 EDX 레지스터의 값은 일반적인 시간의 '초' 단위와 비슷한 간격으로 바뀐다. 프로그램을 빠르게 반복 실행하면 동일한 숫자가 반복되어 나오는걸 알 수 있다. 빠른 반복 추출이 필요하다면 EAX 레지스터의 값 중 하위 2바이트가 아닌 중간 2바이트 숫자를 이용하는 등 다른 방법으로 랜덤 넘버를 추출한다.
※ 주의
DIV 연산시 나누는 수가 작아 몫이 너무 크게 되면 ax가 저장할 수 있는 용량(2바이트)을 넘어서게 되고 Program received signal SIGFPE, arithmetic exception 메세지가 나타난다. Floating-Point Exception을 의미하지만 0으로 나누는 연산과 같은 모든 산술 연산 에러를 포함한다.
'Assembly' 카테고리의 다른 글
[Assembly Language] Setup an Assembly Project on Visual Studio (0) | 2023.01.12 |
---|---|
[Assembly Language] CMOVcc 명령어 활용 (0) | 2023.01.11 |
EMU8086 - MICROPROCESSOR EMULATOR 마이크로 프로세서 에뮬레이터 (0) | 2023.01.05 |
Visual Studio Assembler Output - 비주얼 스튜디오 어셈블리어 코드 생성 (0) | 2023.01.04 |
MASM 6.11 (0) | 2022.12.16 |