4

不使用非标准‡ Scalar_Storage_Order 子句在最近的 GNAT 版本中,IPv4 标头如何通过记录表示子句与任何其他语言特性的任意组合来可移植地表示,以便“相同”的代码在 little-endian 和 big-endian 上都有效-endian 处理器,但以 IETF 所谓的网络字节顺序(这是 IETF 对 big-endian 的花哨名称)的方式在线路上(例如,通过以太网帧的有效负载)发出。在 C 中,“相同”代码可以利用预处理器宏在小端处理器上执行字节交换,但在大端处理器上是无操作的,但标准 Ada 没有预处理器。在 C++ 中,“相同”代码可以利用元模板编程 (MTP) 在小端处理器上执行字节交换,但在大端处理器上是无操作的,但标准 Ada 缺少 MTP。

(顺便说一句,当大端处理器与小端外设IC的内存映射寄存器接口时,设备驱动程序中会出现同样的问题,反之亦然:小端处理器与大端IC的内存映射寄存器接口.)

    BytesPerWord : constant := 4;
    BitsPerByte : constant := 8;
    PowerOf2Highest : constant := BytesPerWord*BitsPerByte - 1; -- part #1 of byte-swap
    type Header_IPv4 is record
          Version   : integer range 0 ..    F#16;
          IHL       : integer range 0 ..    F#16;
          TOS       : integer range 0 ..   FF#16;
          Length    : integer range 0 ..   FF#16;
          Ident     : integer range 0 .. FFFF#16;
          Flags     : integer range 0 ..    7#16;
          Frag_Offs : integer range 0 .. 1FFF#16;
    end record;
    type Header_IPv4_Homogenous is new Header_IPv4;
    for Header_IPv4_Homogenous use record  -- Good-to-go for big-endian processors
          Version   at 0*BytesPerWord range  0 ..  3;
          IHL       at 0*BytesPerWord range  4 ..  7;
          TOS       at 0*BytesPerWord range  8 .. 15;
          Length    at 0*BytesPerWord range 16 .. 31;
          Ident     at 1*BytesPerWord range  0 .. 15;
          Flags     at 1*BytesPerWord range 16 .. 18;
          Frag_Offs at 1*BytesPerWord range 19 .. 31;
    end record;
    for Header_IPv4_Homogenous'Alignment use 4;
    for Header_IPv4_Homogenous'Bit_Order use High_Order_First;
    type Header_IPv4_Heterogenous is new Header_IPv4;
    for Header_IPv4_Heterogenous use record  -- Good-to-go??? for little-endian processors?
          Version   at 0*BytesPerWord range PowerOf2Highest-  3 .. PowerOf2Highest-  0; -- p
          IHL       at 0*BytesPerWord range PowerOf2Highest-  7 .. PowerOf2Highest-  4; -- a
          TOS       at 0*BytesPerWord range PowerOf2Highest- 15 .. PowerOf2Highest-  8; -- r
          Length    at 0*BytesPerWord range PowerOf2Highest- 31 .. PowerOf2Highest- 16; -- t
          Ident     at 1*BytesPerWord range PowerOf2Highest- 15 .. PowerOf2Highest-  0; --
          Flags     at 1*BytesPerWord range PowerOf2Highest- 18 .. PowerOf2Highest- 16; -- #
          Frag_Offs at 1*BytesPerWord range PowerOf2Highest- 31 .. PowerOf2Highest- 19; -- 2
    end record;
    for Header_IPv4_Heterogenous'Alignment use 4;
    for Header_IPv4_Heterogenous'Bit_Order use Low_Order_First; -- part #3 of byte-swap

请注意“PowerOf2Highest minus”和“反转”大端位 id 从 (from,to) 顺序到 [视觉上,而不是算术上真正] (to,from) 顺序在字节交换的第 2 部分中用作粗略相当于 VHDL 的 downto,这是 VHDL 如何解决这种异构字节序问题的关键部分。(VHDL 是 Ada83 的表亲语言。)

但是现在,如何混淆集合 {Header_IPv4_Homogenous, Header_IPv4_Heterogenous} 中的哪个成员已被选为 app-domain-code 中的类型名称 Header_IPv4_Portable?使用子包?

‡ Scalar_Storage_Order已被提议作为下一版 ISO 标准 Ada 的潜在功能,但到目前为止,在 ISO 标准化委员会中还没有正式的赞助商支持该提案,因此标准化提案可能会失败并死去。另外,我将使用非 GNAT Ada 编译器,因此我无法使用 GNAT 特定的功能。

4

1 回答 1

0

大约 20 年前,诺曼·科恩 (Norman Cohen) 在 ada-auth.org/ai-files/grab_bag/bitorder.pdf 中预言了上述解决方案的一部分,但这里和他的文档中缺少的是正确交换的方式通过各种 Ada 编译器中的不同子包记录表示子句。我现在正在寻找如何在所有 Ada 编译器中执行子包条件链接。

这样做的传统方法是通过多个文件,并且项目管理器在编译完成时提供正确的文件。

也许我们可以使用另一种方法;我认为以下应该可以工作,我已经编译了它但还没有测试过:

Package IPv4 is
  Type Header_IPv4 is private;
  Function Version      ( Object : Header_IPv4 ) return Integer;
  Function IHL          ( Object : Header_IPv4 ) return Integer;
  Function TOS          ( Object : Header_IPv4 ) return Integer;
  Function Length       ( Object : Header_IPv4 ) return Integer;
  Function Ident        ( Object : Header_IPv4 ) return Integer;
  Function Flags        ( Object : Header_IPv4 ) return Integer;
  Function Frag_Offs    ( Object : Header_IPv4 ) return Integer;
  -- If you need to write fields, use:
  --   Procedure Field  ( Object : in out Header_IPv4; Value : Integer );

Private
  Header_Size : Constant := 7 * (4*8); -- 7 Integers of 4-bytes.
  type Base_IPv4 is record
     Version   : integer range 0 ..    16#F#;
     IHL       : integer range 0 ..    16#F#;
     TOS       : integer range 0 ..   16#FF#;
     Length    : integer range 0 ..   16#FF#;
     Ident     : integer range 0 .. 16#FFFF#;
     Flags     : integer range 0 ..    16#7#;
     Frag_Offs : integer range 0 .. 16#1FFF#;
  end record
  with Size => Header_Size, Object_Size => Header_Size;

  type Header_IPv4 is null record
  with Size => Header_Size, Object_Size => Header_Size;
End IPv4;


Package Body IPv4 is
  Package Internal is
     Use System;

     BytesPerWord    : constant := 4;
     BitsPerByte     : constant := 8;
     PowerOf2Highest : constant := BytesPerWord*BitsPerByte - 1; -- part #1 of byte-swap

     type Header_IPv4_Homogenous is new Base_IPv4;
     for Header_IPv4_Homogenous use record  -- Good-to-go for big-endian processors
        Version   at 0*BytesPerWord range  0 ..  3;
        IHL       at 0*BytesPerWord range  4 ..  7;
        TOS       at 0*BytesPerWord range  8 .. 15;
        Length    at 0*BytesPerWord range 16 .. 31;
        Ident     at 1*BytesPerWord range  0 .. 15;
        Flags     at 1*BytesPerWord range 16 .. 18;
        Frag_Offs at 1*BytesPerWord range 19 .. 31;
     end record;
     for Header_IPv4_Homogenous'Alignment use 4;
     for Header_IPv4_Homogenous'Bit_Order use High_Order_First;
     type Header_IPv4_Heterogenous is new Base_IPv4;
     for Header_IPv4_Heterogenous use record  -- Good-to-go??? for little-endian processors?
        Version   at 0*BytesPerWord range PowerOf2Highest-  3 .. PowerOf2Highest-  0; -- p
        IHL       at 0*BytesPerWord range PowerOf2Highest-  7 .. PowerOf2Highest-  4; -- a
        TOS       at 0*BytesPerWord range PowerOf2Highest- 15 .. PowerOf2Highest-  8; -- r
        Length    at 0*BytesPerWord range PowerOf2Highest- 31 .. PowerOf2Highest- 16; -- t
        Ident     at 1*BytesPerWord range PowerOf2Highest- 15 .. PowerOf2Highest-  0; --
        Flags     at 1*BytesPerWord range PowerOf2Highest- 18 .. PowerOf2Highest- 16; -- #
        Frag_Offs at 1*BytesPerWord range PowerOf2Highest- 31 .. PowerOf2Highest- 19; -- 2
     end record;
     for Header_IPv4_Heterogenous'Alignment use 4;
     for Header_IPv4_Heterogenous'Bit_Order use Low_Order_First; -- part #3 of byte-swap

     Function Convert_Heterogenous is new Ada.Unchecked_Conversion(
        Source => Header_IPv4,
        Target => Header_IPv4_Heterogenous
       );
     Function Convert_Homogenous is new Ada.Unchecked_Conversion(
        Source => Header_IPv4,
        Target => Header_IPv4_Homogenous
       );
     Function Convert_Heterogenous is new Ada.Unchecked_Conversion(
        Source => Header_IPv4_Heterogenous,
        Target => Header_IPv4
       );
     Function Convert_Homogenous is new Ada.Unchecked_Conversion(
        Source => Header_IPv4_Homogenous,
        Target => Header_IPv4
       );

  End Internal;

  Function Convert( Object : Header_IPv4 ) return Base_IPv4 is
     use Internal, System;
  Begin
     if Default_Bit_Order = High_Order_First then
        Return Base_IPv4( Convert_Homogenous(Object) );
     else
        Return Base_IPv4( Convert_Heterogenous(Object) );
     end if;
  End Convert;


  Function Version      ( Object : Header_IPv4 ) return Integer is
     (Convert(Object).Version);
  Function IHL      ( Object : Header_IPv4 ) return Integer is
     (Convert(Object).IHL);
  Function TOS      ( Object : Header_IPv4 ) return Integer is
     (Convert(Object).TOS);
  Function Length       ( Object : Header_IPv4 ) return Integer is
     (Convert(Object).Length);
  Function Ident        ( Object : Header_IPv4 ) return Integer is
     (Convert(Object).Ident);
  Function Flags        ( Object : Header_IPv4 ) return Integer is
     (Convert(Object).Flags);
  Function Frag_Offs    ( Object : Header_IPv4 ) return Integer is
     (Convert(Object).Frag_Offs);

End IPv4;

另一种选择是使用read/write属性,虽然这种形式不允许内存映射 IPv4 类型的变量并正确读取它,但它应该足以用于基于流的处理,并且比这里的要简单得多。

于 2019-04-30T14:34:13.353 回答