仅在 ISO 标准 Ada 中,记录表示子句 + 任何其他语言功能如何可移植到小端和大端处理器? [英] In only ISO standard Ada, how can Record Representation Clause + any other language feature(s) be portable to little-endian and big-endian processors?

查看:24
本文介绍了仅在 ISO 标准 Ada 中,记录表示子句 + 任何其他语言功能如何可移植到小端和大端处理器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Without utilizing the nonstandard‡ Scalar_Storage_Order clause in recent releases of GNAT, how can, say, the IPv4 header be portably represented via Record Representation Clause(s) in conjunction with any combination of any other language features, so that "the same" code works on both little-endian and big-endian processors but be emitted on the wire (e.g., via, say, the payload of an Ethernet frame) in what IETF calls network byte order (which is IETF's fancy name for big-endian). In C, "the same" code could utilize preprocessor macros to perform byte-swapping on little-endian processors, but be a no-op on big-endian processors, but standard Ada has no preprocessor. In C++, "the same" code could utilize meta-template programming (MTP) to perform byte-swapping on little-endian processors, but be a no-op on big-endian processors, but standard Ada lacks MTP.

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

(Btw, much the same issue arises in a device driver when a big-endian processor interfaces with a little-endian peripheral IC's memory-mapped register, or vice versa: little-endian processor interfaces with a big-endian IC's memory-mapped register.)

    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

注意如何在字节的第 2 部分中使用PowerOf2Highest 减"和反转"大端的位 ID 从(从,到)顺序到[视觉上,实际上不是算术上](到,从)顺序 -交换作为 VHDL downto 的粗略等价物,这是 VHDL 如何解决这个异构字节序问题的关键部分.(VHDL 是 Ada83 的表亲语言.)

Note how "PowerOf2Highest minus" and ‘reversing’ the big-endian's bit ids from (from,to) order to [visually, not arithmetically really] (to,from) order are utilized in part #2 of the byte-swap as a rough equivalent of VHDL's downto, which is a key portion of how VHDL would solve this heterogenous-endianness problem. (VHDL is a cousin language to Ada83.)

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

But now, how to obfuscate which member of the set {Header_IPv4_Homogenous, Header_IPv4_Heterogenous} has been chosen as the type name Header_IPv4_Portable in app-domain-code? Use child packages?

‡ Scalar_Storage_Order 已被提议作为下一版 Ada ISO 标准的潜在特性,但到目前为止,ISO 标准化委员会中还没有官方发起人支持该提案,因此标准化提案可以去哪里&死在藤蔓上.另外,我将使用非 GNAT Ada 编译器,因此我无法使用 GNAT 特定的功能.

‡ Scalar_Storage_Order has been proposed as a potential feature for the next edition of the ISO standard of Ada, but so far there is no official sponsor championing the proposal in the ISO standardization committee, so the proposal for standardization could whither & die on the vine. Plus I shall use a non-GNAT Ada compiler, so using the GNAT-specific feature is unavailable to me.

推荐答案

上述解决方案的一部分由 Norman Cohen 在ada-auth.org/ai-files/grab_bag/bitorder.pdf 大约 20 年前,但是这里和他的文档中缺少的是交换的方式在正确的记录表示子句中,例如,不同的孩子各种 Ada 编译器中的软件包.如何做那个子包所有 Ada 编译器中的条件链接是我正在寻找的现在.

The portion of the solution above was presaged by Norman Cohen in ada-auth.org/ai-files/grab_bag/bitorder.pdf almost 20 years ago, but what is missing both here and in his document is the way of swapping in the correct Record Representation Clause via, say, different child packages in various Ada compilers. How to do that child-package conditional linkage in all the Ada compilers is what I am looking for now.

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

The traditional way to do so would be via multiple files and the project-manager supplying the proper one as the compilation is done.

也许我们可以使用另一种方法;我认为以下应该有效,我已经编译但尚未对其进行测试:

Perhaps there is an alternate method we can use though; I think the following should work, I've compiled it but haven't tested it:

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 类型变量进行内存映射并正确读取它,但它应该足以进行基于流的处理,而且比这里的要简单得多.

Another alternative could be had by using the read/write attributes, although this form would not allow memory-mapping the IPv4-typed variable and correctly reading it, it should suffice for stream-based processing, and much simpler than what's here.

这篇关于仅在 ISO 标准 Ada 中,记录表示子句 + 任何其他语言功能如何可移植到小端和大端处理器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆