在 Ada 中将地址拆分并转换为不同的整数

Split and casting address into different integers in Ada

要与特定硬件接口(在本例中为 x86 GDT 的 TSS 条目),需要在内存中使用以下结构:

type UInt32 is mod 2 ** 32;
type UInt16 is mod 2 ** 16;
type UInt8  is mod 2 ** 8;

type TSSEntry is record
   Limit       : UInt16;
   BaseLow16   : UInt16;
   BaseMid8    : UInt8;
   Flags1      : UInt8;
   Flags2      : UInt8;
   BaseHigh8   : UInt8;
   BaseUpper32 : UInt32;
   Reserved    : UInt32;
end record;
for TSSEntry use record
   Limit       at 0 range 0  .. 15;
   BaseLow16   at 0 range 16 .. 31;
   BaseMid8    at 0 range 32 .. 39;
   Flags1      at 0 range 40 .. 47;
   Flags2      at 0 range 48 .. 55;
   BaseHigh8   at 0 range 56 .. 63;
   BaseUpper32 at 0 range 64 .. 95;
   Reserved    at 0 range 96 .. 127;
end record;
for TSSEntry'Size use 128;

当运行将一些C代码写入Ada时,我运行遇到了几个问题,我在网上找不到很多资源。 C 代码段是:

TSSEntry tss;

void loadTSS(size_t address) {
    tss.baseLow16   = (uint16_t)address;
    tss.baseMid8    = (uint8_t)(address >> 16);
    tss.flags1      = 0b10001001;
    tss.flags2      = 0;
    tss.baseHigh8   = (uint8_t)(address >> 24);
    tss.baseUpper32 = (uint32_t)(address >> 32);
    tss.reserved    = 0;
}

这是我尝试将其转换为的 Ada 代码运行:

TSS : TSSEntry;

procedure loadTSS (Address : System.Address) is
begin
   TSS.BaseLow16   := Address; --  How would I downcast this to fit in the 16 lower bits?
   TSS.BaseMid8    := Shift_Right(Address, 16); -- Bitwise ops dont take System.Address + downcast
   TSS.Flags1      := 2#10001001#;
   TSS.Flags2      := 0;
   TSS.BaseHigh8   := Shift_Right(Address, 24); -- Same as above
   TSS.BaseUpper32 := Shift_Right(Address, 32); -- Same as above
   TSS.Reserved    := 0;
end loadTSS;

我怎样才能显示我在代码中突出显示的问题?在这种情况下,初学者是否可以使用任何资源来寻求帮助?提前致谢!

使用包 System.Storage_Elements 中的 To_Integer 函数将地址转换为整数,然后将该整数转换为接口。Unsigned_32 或 Unsigned_64(以哪个为准适当的)以便您可以使用移位操作来提取位域。

除了移位和掩码操作,您当然可以使用除法和“mod”来分离整数,而无需转换为接口类型。