I have run into a problem with both 4.6.1 and 4.7.2 of the gcc compiler handling type short. Sizeof(unsigned short) returns a length of 2 as expected, but when I use a union of a character buffer and some fields including a unsigned short the value returned is 2 bytes but the buffer pointer is moved 4 bytes.

Here is the code for the union of the fs structure with the buffer (the super block structure and union are at the bottom of the listing):

/* taken from filsys.h for Intel Xenix */
#define    u_short    unsigned short
#define    daddr_t    unsigned int
#define    ino_t    unsigned short
#define    time_t    unsigned int

#define FS_CLEAN    106
#define    BMAPSIZE    994        /* Max size of CG bit map */
                    /* Equals BSIZE-sizeof(struct cylinder)*/

#define MAXCGS        80        /* Max CG's per filsys */
#define    MAXEXTSIZE    32        /* Max extent size */
#define FNEWCG        64        /* When a file grows beyond FNEWCG KB,
                       allocate blocks from a new
                       cylinder group */
#define SNEWCG        512        /* Move to a new cylinder group after
                       every subsequent SNEWCG KB */

/*
 * Cylinder group header
 */
struct cylinder {
daddr_t cg_doffset; /* offset to first data block from start of filsys */ daddr_t cg_ioffset; /* offset to first inode block from start of filsys */
    u_short        cg_dblocks;            /* number of data blocks in cg */
    ino_t        cg_ifirst;            /* next free inode in linked list */
    char        cg_number;            /* cg sequence number in filsys */
    char        cg_currextent;        /* current extent size */
u_short cg_lowat; /* if free blocks drop below cg_lowat, recompute cg_currextent */ u_short cg_hiwat; /* if free blocks increase beyond cg_hiwat, recompute cg_currextent */ u_short cg_erotor; /* position of next candidate block for allocation */
    char        cg_ilock;            /* inode manipulation lock */
char cg_reserved[9]; /* reserved field. (9 to align on word boundary) */ char cg_bits[BMAPSIZE]; /* bit map. 0 = allocated. 1 = free */
};

/*
 * Contains global policy information.
 * Stored in the superblock.
 */
struct    cginfo {
u_short fs_cgincore; /* points to buf structure containing cg header. Null if not in core */
    daddr_t        fs_cgblk;            /* disk address of cg header */
u_short fs_cgffree; /* number of free data blocks in cg */
    ino_t        fs_cgifree;            /* number of free inodes in cg */
    ino_t        fs_cgdirs;            /* number of directories in cg */
};

/*
 * Super block
 */
struct filsys {
    char        fs_fname[6];        /* file system name */
    char        fs_fpack[6];        /* pack name */
    daddr_t        fs_fsize;            /* number of data blocks in fs */
    u_short        fs_cgblocks;        /* number of blocks per cg */
    daddr_t        fs_maxblock;        /* max disk block in fs */
    ino_t        fs_cginodes;        /* number of inodes per cg */
    ino_t        fs_maxino;            /* max inumber in fs */
    time_t        fs_time;            /* time last modified */
    char        fs_fmod;            /* modified flag */
    char        fs_ronly;            /* read-only fs */
    char        fs_clean;            /* fs was cleanly unmounted */
    char        fs_type;            /* fs type and version */
    u_short        fs_fnewcg;            /* contains FNEWCG */
    u_short        fs_snewcg;            /* contains SNEWCG */
daddr_t fs_ffree; /* number of free data blocks in fs */
    ino_t        fs_ifree;            /* number of free inodes in fs */
    ino_t        fs_dirs;            /* number of directories in fs */
    char        fs_extentsize;        /* native extent size */
    char        fs_cgnum;            /* number of cg's in fs */
    char        fs_cgrotor;            /* next cg to be searched */
char fs_reserved[15]; /* reserved. (15 to align on word boundary) */ struct cginfo fs_cylinder[MAXCGS];/* contains global policy information
                                    per cylinder group */
};

I use this routine to to dump the info from the superblock:

void dumpsuper(void)
{
    if (*super.fs.fs_fname)
        printf("fs_fname = %s\n", super.fs.fs_fname);
    if (*super.fs.fs_fname)
        printf("fs_fpack = %s\n", super.fs.fs_fpack);
    printf("fs_fsize = %d\n", super.fs.fs_fsize);
    printf("fs_cgblocks = %d\n", super.fs.fs_cgblocks);
    printf("fs_maxblock = %d\n", super.fs.fs_maxblock);
    printf("fs_cginodes = %d\n", super.fs.fs_cginodes);
    printf("fs_maxino = %d\n", super.fs.fs_maxino);
    printf("len = %d\n", sizeof(unsigned short));
    dumphex(1024, 256);
}

When run, I get this result:

MAKIMG Intel Xenix Version 6.0 starting...
fs_fsize = 354
fs_cgblocks = 358
fs_maxblock = 3145728
fs_cginodes = 48
fs_maxino = 36234
len = 2
000400 00 00 00 00 00 00 00 00 00 00 00 00 62 01 00 00 ............b...
000410 66 01 67 01 00 00 30 00 30 00 8A 8D E6 1B 00 00 f.g...0.0.......
000420 6A 00 40 00 00 02 10 00 00 00 19 00 07 00 08 01 j.@.............
000430 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000440 00 00 02 00 00 00 10 00 19 00 07 00 00 00 00 00 ................
000450 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000460 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000470 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000480 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000490 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0004A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0004B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0004C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0004D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0004E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0004F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

As you can see the value at 0410 in the file, 6601 is returned as 358, which is correct. The 4-byte value following 67 01 00 00 is not returned for the unsigned int but rather 00 00 30 00 is returned next (which equals 3145728 decimal). While a sizeof(unsigned short) returns 2 bytes, in this case the pointer into the unioned buffer is moved 4 bytes.

This bug makes it hell to you any of your products to build emulators for the 16-bit processors.

Is there a definition for a 16-bit quantity that will work in a union?

Thanks!

Bill Beech
NJ7P

Reply via email to