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