「X86」の版間の差分
提供: Wikinote
(新しいページ: ' == レジスタ == === 汎用レジスタ === これらは 32 ビットである。'E' を省いたものが下位 16 ビットを示す。 また、A - D までは、?L で...') |
細 (→64 ビットモード) |
||
| (同じ利用者による、間の8版が非表示) | |||
| 行1: | 行1: | ||
| + | そのうちアセンブリ言語も読まなきゃならなくなりそうなので。 | ||
| + | |||
| + | == 参考文献 == | ||
| + | * [http://www.intel.co.jp/products/processor/manuals/index.htm Intel® 64 and IA-32 Architectures Software Developer's Manuals] | ||
| + | ** Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 1: Basic Architecture | ||
== レジスタ == | == レジスタ == | ||
| 行15: | 行20: | ||
==== 64 ビットモード ==== | ==== 64 ビットモード ==== | ||
64 ビットモードでは、以下の 16 個の汎用レジスタが利用できる。 | 64 ビットモードでは、以下の 16 個の汎用レジスタが利用できる。 | ||
| − | + | これらはそれぞれ、下位 32 ビットのみアクセスすることも可能だ。 | |
| − | ; 64 | + | ; 64 ビットアクセス |
: RAX, RBX, RCX, RDX, RDI, RSI, RBP, RSP, R8 - R15 | : RAX, RBX, RCX, RDX, RDI, RSI, RBP, RSP, R8 - R15 | ||
| − | ; 32 | + | ; 32 ビットアクセス |
: EAX, EBX, ECX, EDX, EDI, ESI, EBP, ESP, R8D - R15D | : EAX, EBX, ECX, EDX, EDI, ESI, EBP, ESP, R8D - R15D | ||
| + | |||
| + | ところで、32 ビット OS でも <code>long long int</code> を定義すると 8 バイトの整数が定義できるが、 | ||
| + | これはどのように処理されているのだろうか?実験してみた。 | ||
| + | [hagio@lab ~]$ cat > 64bit.c | ||
| + | int main(void) { | ||
| + | long long int s64, r64; | ||
| + | s64 = 0x1000000000000000LL; | ||
| + | r64 = s64 + 1; | ||
| + | return 0; | ||
| + | } | ||
| + | [hagio@lab ~]$ cc -S 64bit.c | ||
| + | [hagio@lab ~]$ cat 64bit.s | ||
| + | .file "64bit.c" | ||
| + | .text | ||
| + | .globl main | ||
| + | .type main, @function | ||
| + | main: | ||
| + | leal 4(%esp), %ecx | ||
| + | andl $-16, %esp | ||
| + | pushl -4(%ecx) | ||
| + | pushl %ebp | ||
| + | movl %esp, %ebp | ||
| + | pushl %ecx | ||
| + | subl $20, %esp | ||
| + | ★movl $0, -24(%ebp) | ||
| + | ★movl $268435456, -20(%ebp) | ||
| + | movl -24(%ebp), %eax | ||
| + | movl -20(%ebp), %edx | ||
| + | ☆addl $1, %eax | ||
| + | ☆adcl $0, %edx | ||
| + | movl %eax, -16(%ebp) | ||
| + | movl %edx, -12(%ebp) | ||
| + | movl $0, %eax | ||
| + | addl $20, %esp | ||
| + | popl %ecx | ||
| + | popl %ebp | ||
| + | leal -4(%ecx), %esp | ||
| + | ret | ||
| + | .size main, .-main | ||
| + | .ident "GCC: (GNU) 4.1.2 20071124 (Red Hat 4.1.2-42)" | ||
| + | .section .note.GNU-stack,"",@progbits | ||
| + | おもろい。単に 4 バイトずつ 2 回に分けて計算しているだけのようだ。 | ||
| + | ただ、下位 4 バイトは下位 4 バイト同士普通に加算して、上位 4 バイトはキャリー付きの加算を行っている。 | ||
| + | つまり、下位 4 バイトの加算結果があふれたら、上位 4 バイトに 1 を足す。 | ||
| + | これにより、2 回に分けても上手く計算できるようになっている。おもろい!! | ||
| + | 乗算などの他の計算だとどうなるか… すでにやってみたのは言うまでもないが、余白がないので省略する。 | ||
| + | (ぜひいろいろ試してみてほしい…。) | ||
| + | |||
| + | 64 ビットマシンだとどうなるのか気になる… (答えはわかるけどやらなきゃ気がすまない)。 | ||
| + | |||
| + | === セグメントレジスタ === | ||
| + | すべて 16 ビット幅である。 | ||
| + | * CS — Code segment register | ||
| + | * DS, ES, FS, GS — Data segment register | ||
| + | * SS — Stack segment register | ||
| + | |||
| + | === フラグレジスタ === | ||
| + | ; EFLAGS | ||
| + | : 32 ビット幅で、プロセッサ初期化後の値は 0x00000002 となる。 | ||
| + | |||
| + | ==== ステータスフラグ ==== | ||
| + | * CF (bit 0) — Carry flag | ||
| + | * PF (bit 2) — Parity flag | ||
| + | * AF (bit 4) — Adjust flag | ||
| + | * ZF (bit 6) — Zero flag | ||
| + | * SF (bit 7) — Sign flag | ||
| + | * OF (bit 11) — Overflow flag | ||
| + | |||
| + | フラグは多すぎて面倒なのでまたやる気が出たら… | ||
| + | |||
| + | === 命令ポインタ === | ||
| + | ; EIP (RIP) | ||
| + | : 32 ビット幅 (64 ビット幅) | ||
2009年9月11日 (金) 21:16時点における最新版
そのうちアセンブリ言語も読まなきゃならなくなりそうなので。
参考文献
- Intel® 64 and IA-32 Architectures Software Developer's Manuals
- Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 1: Basic Architecture
レジスタ
汎用レジスタ
これらは 32 ビットである。'E' を省いたものが下位 16 ビットを示す。 また、A - D までは、?L で下位 0-7 ビット、?H で 下位 8-15 ビットを示す。
- EAX — Accumulator for operands and results data
- EBX — Pointer to data in the DS segment
- ECX — Counter for string and loop operations
- EDX — I/O pointer
- ESI — Pointer to data in the segment pointed to by the DS register; source pointer for string operations
- EDI — Pointer to data (or destination) in the segment pointed to by the ES register; destination pointer for string operations
- ESP — Stack pointer (in the SS segment)
- EBP — Pointer to data on the stack (in the SS segment)
64 ビットモード
64 ビットモードでは、以下の 16 個の汎用レジスタが利用できる。 これらはそれぞれ、下位 32 ビットのみアクセスすることも可能だ。
- 64 ビットアクセス
- RAX, RBX, RCX, RDX, RDI, RSI, RBP, RSP, R8 - R15
- 32 ビットアクセス
- EAX, EBX, ECX, EDX, EDI, ESI, EBP, ESP, R8D - R15D
ところで、32 ビット OS でも long long int を定義すると 8 バイトの整数が定義できるが、
これはどのように処理されているのだろうか?実験してみた。
[hagio@lab ~]$ cat > 64bit.c
int main(void) {
long long int s64, r64;
s64 = 0x1000000000000000LL;
r64 = s64 + 1;
return 0;
}
[hagio@lab ~]$ cc -S 64bit.c
[hagio@lab ~]$ cat 64bit.s
.file "64bit.c"
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $20, %esp
★movl $0, -24(%ebp)
★movl $268435456, -20(%ebp)
movl -24(%ebp), %eax
movl -20(%ebp), %edx
☆addl $1, %eax
☆adcl $0, %edx
movl %eax, -16(%ebp)
movl %edx, -12(%ebp)
movl $0, %eax
addl $20, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (GNU) 4.1.2 20071124 (Red Hat 4.1.2-42)"
.section .note.GNU-stack,"",@progbits
おもろい。単に 4 バイトずつ 2 回に分けて計算しているだけのようだ。 ただ、下位 4 バイトは下位 4 バイト同士普通に加算して、上位 4 バイトはキャリー付きの加算を行っている。 つまり、下位 4 バイトの加算結果があふれたら、上位 4 バイトに 1 を足す。 これにより、2 回に分けても上手く計算できるようになっている。おもろい!! 乗算などの他の計算だとどうなるか… すでにやってみたのは言うまでもないが、余白がないので省略する。 (ぜひいろいろ試してみてほしい…。)
64 ビットマシンだとどうなるのか気になる… (答えはわかるけどやらなきゃ気がすまない)。
セグメントレジスタ
すべて 16 ビット幅である。
- CS — Code segment register
- DS, ES, FS, GS — Data segment register
- SS — Stack segment register
フラグレジスタ
- EFLAGS
- 32 ビット幅で、プロセッサ初期化後の値は 0x00000002 となる。
ステータスフラグ
- CF (bit 0) — Carry flag
- PF (bit 2) — Parity flag
- AF (bit 4) — Adjust flag
- ZF (bit 6) — Zero flag
- SF (bit 7) — Sign flag
- OF (bit 11) — Overflow flag
フラグは多すぎて面倒なのでまたやる気が出たら…
命令ポインタ
- EIP (RIP)
- 32 ビット幅 (64 ビット幅)