第 2 章後半は正直写経する箇所がない・・・というか、一部だけ消して何も考えずに写経するくらいしかなさそうなので、オフィシャルからコードを持ってきてビルドして解説を読むだけにした。コードの内容自体はよくありがちなものに見えるからまぁ良かろう。
for 文の中身で最初にやっているのは整数からポインタへのキャスト(型変換)です
とあるので、コードからすると EFI_PHYSICAL_ADDRESS
が整数型の define
か typedef
なんだろうなぁ・・・と思って確認したらそうだった。なんでだ・・・。おかげで、ポインタ→整数→ポインタのキャストが起こってそう。
MdePkg/Include/Uefi/UefiBaseType.h
で以下のように定義されている:
/// /// 64-bit physical memory address. /// typedef UINT64 EFI_PHYSICAL_ADDRESS;
6.3.2.3 Pointers
[...]
5 An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.
6 Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type.
なので一般論としては嫌なんだけど、大抵動くんだろうし、よく見る内容でもある。C++ の場合は n4140.pdf (C++14 draft) によると
5.2.10 Reinterpret cast
[...]
4 A pointer can be explicitly converted to any integral type large enough to hold it. The mapping function is implementation-defined. A value of type std::nullptr_t can be converted to an integral type; the conversion has the same meaning and validity as a conversion of (void*)0 to the integral type.
5 A value of integral type or enumeration type can be explicitly converted to a pointer. A pointer converted to an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will have its original value; mappings between pointers and integers are otherwise implementation-defined.
ということで、「十分に大きい」サイズの整数に変換して同じ型のポインタに戻す場合は同じ値だよと。これも同じく大抵動く。C11 と C++14 で微妙に書き方のニュアンスが違うのが嫌だな・・・。
それはさて置き Qemu で実行すると
となって、メモリマップが dump される。disk.img
に書き出されているはずなので、これをマウントして memmap
ファイルを取り出すと、
Index, Type, Type(name), PhysicalStart, NumberOfPages, Attribute 0, 3, EfiBootServicesCode, 00000000, 1, F 1, 7, EfiConventionalMemory, 00001000, 9F, F 2, 7, EfiConventionalMemory, 00100000, 700, F 3, A, EfiACPIMemoryNVS, 00800000, 8, F 4, 7, EfiConventionalMemory, 00808000, 8, F 5, A, EfiACPIMemoryNVS, 00810000, F0, F 6, 4, EfiBootServicesData, 00900000, B00, F 7, 7, EfiConventionalMemory, 01400000, 3AB36, F ...
のようになっている。
ポインタのポインタの話は、よくありがちな
typedef void *HANDLE; int getHandle(HANDLE* handle);
みたいなこと考えたら良さそうだし、ざっと読んで終わり。考え出すとつらいから適当に脳内で typedef
挟むと良さそう。これで第 2 章後半(〜p.66)は終わり。