/*
 *  smoke16/include/smoke16/a_out.h - A description of the SMOKE-16 executable format
 *  $Revision: 1.32 $
 *  Copyright 1997-2002, Benjamin Sittler
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

/* This file describes the a.out executable format
 * as used by the SMOKE-16 toolset.
 *
 * All values are stored in the file in packed big-endian format and
 * converted by the fget16*()/fput16*() functions -- see libObj.h.
 * Sizes of structures in the file should be computed using the
 * fsz16*() macros, not sizeof().
 */

#ifndef SMOKE16__A_OUT_H_INCLUDED
#define SMOKE16__A_OUT_H_INCLUDED

/* current toolset version and release */
#define SMOKE16_TOOLVERSION    ((u16) 1U)
#define SMOKE16_RELEASE        "20020728"

#include <smoke16/types.h>

/* This is the SMOKE-16 toolset warranty */
#define SMOKE16_WARRANTY \
   "SMOKE-16 toolset version %" FMT_u16 " release " SMOKE16_RELEASE "\n" \
   "Copyright 1997-2002, Benjamin C. W. Sittler\n\n" \
   "This software is distributed with NO WARRANTY of any sort, and\n" \
   "is intended for no particular purpose.\n\n" \
   "This is free software redistributable under the terms of the GNU\n" \
   "General Public License, version 2 or (at your option) any later version.\n" \
   "See the file COPYING for details, or write to the Free Software\n" \
   "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"

/* SMOKE-16 Exec header */

struct a_out16_exec {
  u16 a_info; /* use SMOKE16_A_* access macros and SMOKE16_SET_A_* set macros */
  u16 a_magic; /* SMOKE16_*MAGIC */
  u32 a_text; /* length of text section in bytes (u16 in "v0" files) */
  u32 a_data; /* length of data section in bytes (u16 in "v0" files) */
  u16 a_bss; /* length of uninitialized data section in bytes */
  u16 a_syms; /* length of symbol table in bytes */
  u16 a_entry; /* absolute address of entry point */
  u16 a_trsize; /* length of text relocations in bytes */
  u16 a_drsize; /* length of data relocations in bytes */
};

#define fsz16exec(toolversion) ((size_t) (((toolversion) == ((u16) 0U) ? 18 : 22))

#define M_SMOKE16 ((u16) 120U) /* machtype for the SMOKE-16 architecture */

/* unsupported magic numbers */
#define SMOKE16_QMAGIC ((u16) 0314U) /* paged executable (1st page unmapped) */
#define SMOKE16_MAGIC0 ((u16) 0401U) /* lpd thingummy */
#define SMOKE16_MAGIC4 ((u16) 0405U) /* overlay */
#define SMOKE16_ZMAGIC ((u16) 0413U) /* paged executable */
#define SMOKE16_MAGIC5 ((u16) 0437U) /* split I&D system overlay */

/* All of the objects and executables here assume the Mirrors system
 * call interface. For the moment this is implicit, since Mirrors is
 * the only SMOKE-16 system call interface.
 */

/* supported magic numbers */
#define SMOKE16_OMAGIC ((u16) 0407U) /* object or impure executable */
#define SMOKE16_NMAGIC ((u16) 0410U) /* pure executable */
#define SMOKE16_JMAGIC ((u16) 0411U) /* split I&D executable */
#define SMOKE16_LMAGIC ((u16) 0440U) /* object archive */

#define SMOKE16_N_BADMAG(x) (((x).a_magic) != SMOKE16_OMAGIC && \
			     ((x).a_magic) != SMOKE16_NMAGIC && \
			     ((x).a_magic) != SMOKE16_JMAGIC && \
			     ((x).a_magic) != SMOKE16_LMAGIC)

#define SMOKE16_A_DYNAMIC(x) ((x).a_info >> 15)
#define SMOKE16_A_TOOLVERSION(x) (((x).a_info >> 8) & ((u16) 0x7fU))
#define SMOKE16_A_MACHTYPE(x) ((x).a_info & ((u16) 0xffU))
/* use of SMOKE16__SET_A_INFO is discouraged */
#define SMOKE16__SET_A_INFO(x, dynamic, toolversion, machtype) \
   ((x).a_info = (((dynamic) << 15) | \
    (((toolversion) & ((u16) 0x7fU)) << 8) | \
    ((machtype) & ((u16) 0xffU))))
#define SMOKE16_SET_A_DYNAMIC(x, dynamic) \
   SMOKE16__SET_A_INFO((x), (dynamic), SMOKE16_A_TOOLVERSION(x), SMOKE16_A_MACHTYPE(x))
#define SMOKE16_SET_A_TOOLVERSION(x, toolversion) \
   SMOKE16__SET_A_INFO((x), SMOKE16_A_DYNAMIC(x), (toolversion), SMOKE16_A_MACHTYPE(x))
#define SMOKE16_SET_A_MACHTYPE(x, machtype) \
   SMOKE16__SET_A_INFO((x), SMOKE16_A_DYNAMIC(x), SMOKE16_A_TOOLVERSION(x), (machtype))

/* SMOKE-16 LMAGIC directory entry */

struct a_out16_dirent {
  u16 d_strx; /* string-table offset of member name */
  u16 d_magic; /* copy of member's magic number; used as a sanity check */
  u32 d_value; /* offset to member in data section */
  u32 d_size; /* size of member in data section */
  s32 d_mtime; /* member's modification time */
};

#define fsz16dirent(toolversion) ((size_t) 16)

/* SMOKE-16 Relocations */

/* a relocation entry */
struct a_out16_reloc {
  u16 r_addr_high; /* offsets in section of high and low bytes of address to relocate */
  u16 r_addr_low;
  u16 r_index; /* symbol ordinal (if SMOKE16_R_EXTERN), or SMOKE16_N_* section */
  u16 r_info; /* use SMOKE16_R_* access macros and SMOKE16_SET_R_* set macros */
  u16 r_value; /* offset from symbol or section start */
};

#define fsz16reloc(toolversion) ((size_t) 10)

#define SMOKE16_RELOC_ABSOLUTE	((u16) 0U) /* absolute addressing */
#define SMOKE16_RELOC_DISP8	((u16) 1U) /* %pc-relative addressing (branch instruction)*/

#define SMOKE16_R_EXTERN(x) ((x).r_info >> 15)
#define SMOKE16_R_HIGH(x) (((x).r_info & ((u16) 0x4000U)) >> 14)
#define SMOKE16_R_LOW(x) (((x).r_info & ((u16) 0x2000U)) >> 13)
#define SMOKE16_R_TYPE(x) ((x).r_info & ((u16) 3U))
/* use of SMOKE16__SET_R_INFO is discouraged */
#define SMOKE16__SET_R_INFO(x, extern, high, low, type) \
   ((x).r_info = (((extern) << 15) | \
		  (((high) << 14) & ((u16) 0x4000U)) | \
		  (((low) << 13) & ((u16) 0x2000U)) | \
		  ((type) & ((u16) 3U))))
#define SMOKE16_SET_R_EXTERN(x, extern) \
   SMOKE16__SET_R_INFO((x), (extern), SMOKE16_R_HIGH(x), SMOKE16_R_LOW(x), SMOKE16_R_TYPE(x))
#define SMOKE16_SET_R_HIGH(x, high) \
   SMOKE16__SET_R_INFO((x), SMOKE16_R_EXTERN(x), (high), SMOKE16_R_LOW(x), SMOKE16_R_TYPE(x))
#define SMOKE16_SET_R_LOW(x, low) \
   SMOKE16__SET_R_INFO((x), SMOKE16_R_EXTERN(x), SMOKE16_R_HIGH(x), (low), SMOKE16_R_TYPE(x))
#define SMOKE16_SET_R_TYPE(x, type) \
   SMOKE16__SET_R_INFO((x), SMOKE16_R_EXTERN(x), SMOKE16_R_HIGH(x), SMOKE16_R_LOW(x), (type))

/* SMOKE-16 symbol table entry */
struct a_out16_nlist {
  u16 n_strx; /* offset of symbol name in string table */
  u8 n_type; /* SMOKE16_N_* */
  s8 n_other; /* stab "other" field */
  s16 n_desc; /* stab "desc" field */
  u16 n_value; /* value or offset in section */
};

#define fsz16nlist(toolversion) ((size_t) 8)

#define SMOKE16_N_UNDF	((u8) 0x00U) /* undefined/common */
#define SMOKE16_N_ABS	((u8) 0x02U) /* absolute address */
#define SMOKE16_N_TEXT	((u8) 0x04U) /* text section */
#define SMOKE16_N_DATA	((u8) 0x06U) /* data section */
#define SMOKE16_N_BSS	((u8) 0x08U) /* uninitialized data ("Block Started by Symbol") */
#define SMOKE16_N_ALIGN	((u8) 0x0cU) /* alignment shift */
#define SMOKE16__N_COMM	((u8) 0x12U) /* common (do not use in object files) */
#define SMOKE16_N_EXT	((u8) 0x01U) /* flag */
#define SMOKE16_N_TYPE		((u8) 0x1eU) /* mask */
#define SMOKE16_N_STAB		((u8) 0xe0U) /* mask */

/* special alignment symbols */
#define SMOKE16__ALIGN_TEXT	"@t" /* text section alignment */
#define SMOKE16__ALIGN_DATA	"@d" /* data section alignment */
#define SMOKE16__ALIGN_BSS	"@b" /* uninitialized data section alignment */

#endif /* SMOKE16__A_OUT_H_INCLUDED */
