Offsets do not match

Problem: The offsets between fields in the GCC structures versus the IBM® compiler structures versus the assembler structures do not match.

Solution: You can use elfaggr, an offline Linux® program provided with the z/TPF system, and assembler listings to compare offsets between C/C++ structures and assembler data macros (DSECTs). The source for elfaggr is in the base/util/src directory and the executable is in the linux/bin directory. To display the C/C++ structures that are included in a program, enter one of the following commands on your Linux system:
  • elfaggr objectfilepath.o, where objectfilepath is the full path of the object file name.
  • elfaggr csofilepath.so, where csofilepath is the full path of the C shared object (CSO) file name.
    The following example shows an excerpt of the output displayed of the C/C++ structures that are included in the cvbv program. All structures in the header file or source file are part of the complete output. The cvbv program was specified by entering elfaggr cvbv.o or elfaggr base/load/CVBV.so on a Linux system.
    0x   0      struct opcode_table_entry
    0x   0      short unsigned int opcode
    0x   4      int oplen
    0x   8      unsigned char[38] description
    0x  2E      unsigned char[6] text
    0x  34      DISASM_TYPE type
    0x  38      int format_nbr
    0x  40      struct opcode_table_entry* subtable
    
The following lists some of the possible causes for this problem:
  • Ensure that all fields defined are the same size. See Mapping data types for a list of C data types that have changed size between the IBM C/C++ compiler and GCC.
  • 8-byte pointers and longs are forced to 8-byte boundaries in GCC. This can cause GCC to pad the structure to force boundary alignment where this padding did not exist in the IBM compiler or assembler structure.
  • When bit fields are in unpacked structures, the padding that is applied by various compilers can be different. For example, if you defined a bit field in the following unpacked structure, GCC adds 2 bytes of padding between the c2 and myfield variables, but the IBM compiler does not.
    struct mystruct {
      char c1;
      char c2;
      int myfield :24;
      char c3;
    }

    To address this difference, always pack the structure that contains the bit field. See Migrating your application programs for information about how to pack a structure.

    Note: Consider bit-field variable myfield in the following example:
    struct mystruct {
    ...
    int myfield :24;
    ...
    
    The following is an example of a corresponding elfaggr display:
    0x   0      struct mystruct
    ...
    0x  11: 8   unsigned int myfield:18
    ...
    
    
    Where:
    • The offset for bit-field variable myfield is 0x 11: 8, which means offset 0x11 + 0x8 bits (0x11 bytes + 0x1 byte). This is equal to offset 0x12 (decimal 18).
    • The length of bit-field variable myfield is :18, which means that the field is 0x18 (decimal 24) bits long.
  • If there is a pointer to a pointer to a 4-byte field, ensure that you use both the__ptr32_t data type and the PTR32ATT attribute. For example, consider the following 4-byte field in the ctk2 structure in the c_ck2sn.h header file:
    POINTER *ck2rvt1a;            //void **ck2rvt1a
    To keep the size of this field 4 bytes long, code the following:
    #include <sys/types.h>
    __ptr32_t * PTR32ATT ck2rvt1a;

    If the PTR32ATT attribute is not specified, the size of this field will be 8 bytes and will not match the assembler structure.

  • In the IBM compiler, enumerated data types use the smallest amount of storage possible based on the value of the enumerations. This means that the IBM compiler uses 1, 2, or 4 bytes for an enumerated type. The GCC always uses 4 bytes. As a result, the size of structures that contain enumerated types will change and the relative location of the enumerations will shift. See Mapping data types for more information about how to handle enumerated data types.
Note: The __attribute__((packed)) keyword and attribution specification of the GCC compiler affects only the definition of the data object that the statement directly applies to. If there is a nested inner aggregate (structure or union) in this same definition, the inner definition will not be packed unless __attribute__((packed)) is applied to it as well. That is, packing an outer aggregate definition will not pack any inner definition that might be present.

This also is true for the _Packed qualifier of the z/OS® compiler; that is, if you specify the _Packed qualifier on a structure or union that contains a structure or union as a member, the qualifier is not passed on to the contained structure or union. You must specify the _Packed qualifier on any nested inner aggregate (structure or union) that is in this same definition.