commit 9055a46c626d315901697e1665225c492a582a8e Author: Kelvin Sherlock Date: Sat Dec 24 14:58:55 2016 -0500 . diff --git a/dumpobj.cpp b/dumpobj.cpp new file mode 100644 index 0000000..06a6af1 --- /dev/null +++ b/dumpobj.cpp @@ -0,0 +1,508 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "obj816.h" + +enum class endian { + little = __ORDER_LITTLE_ENDIAN__, + big = __ORDER_BIG_ENDIAN__, + native = __BYTE_ORDER__ +}; + + +template +void swap_if(T &t, std::false_type) {} + +void swap_if(uint8_t &, std::true_type) {} + +void swap_if(uint16_t &value, std::true_type) { + value = __builtin_bswap16(value); +} + +void swap_if(uint32_t &value, std::true_type) { + value = __builtin_bswap32(value); +} + +void swap_if(uint64_t &value, std::true_type) { + value = __builtin_bswap64(value); +} + + + +template +void le_to_host(T &value) { + swap_if(value, std::integral_constant{}); +} + +void usage() { + exit(EX_USAGE); +} + +#pragma pack(push, 1) +struct Header { + uint32_t h_magic; /* magic number for detection */ + uint16_t h_version; /* version number of object format */ + uint8_t h_filtyp; /* file type, object or library */ +}; + +#pragma pack(pop) + + + + +template +uint8_t read_8(T &iter) { + uint8_t tmp = *iter; + ++iter; + return tmp; +} + +template +uint16_t read_16(T &iter) { + uint16_t tmp = 0; + + tmp |= *iter << 0; + ++iter; + tmp |= *iter << 8; + ++iter; + return tmp; +} + +template +uint16_t read_32(T &iter) { + uint32_t tmp = 0; + + tmp |= *iter << 0; + ++iter; + tmp |= *iter << 8; + ++iter; + tmp |= *iter << 16; + ++iter; + tmp |= *iter << 24; + ++iter; + + + return tmp; +} + +template +std::string read_cstring(T &iter) { + std::string s; + for(;;) { + uint8_t c = *iter; + ++iter; + if (!c) break; + s.push_back(c); + } + return s; +} + + +template +std::string read_pstring(T &iter) { + std::string s; + unsigned size = *iter; + ++iter; + s.reserve(size); + while (size--) { + uint8_t c = *iter; + ++iter; + s.push_back(c); + } + return s; +} + +void dump_obj(const char *name, int fd) +{ + static const char *sections[] = { "PAGE0", "CODE", "KDATA", "DATA", "UDATA" }; + static const char *types[] = { "S_UND", "S_ABS", "S_REL", "S_EXP", "S_REG", "S_FREG" }; + + Mod_head h; + ssize_t ok; + + ok = read(fd, &h, sizeof(h)); + if (ok != sizeof(h)) + errx(EX_DATAERR, "%s is not an object file", name); + + + le_to_host(h.h_magic); + le_to_host(h.h_version); + le_to_host(h.h_filtyp); + le_to_host(h.h_namlen); + le_to_host(h.h_recsize); + le_to_host(h.h_secsize); + le_to_host(h.h_symsize); + le_to_host(h.h_optsize); + le_to_host(h.h_tot_secs); + le_to_host(h.h_num_secs); + le_to_host(h.h_num_syms); + + assert(h.h_magic == MOD_MAGIC); + assert(h.h_version == 1); + assert(h.h_filtyp == 1); + + // now read the name (h_namlen includes 0 terminator.) + std::vector oname; + oname.resize(h.h_namlen); + ok = read(fd, oname.data(), h.h_namlen); + if (ok != h.h_namlen) errx(EX_DATAERR, "%s", name); + + + printf("name: %s\n", oname.data()); + printf("record size: %04x\n", h.h_recsize); + printf("section size: %04x\n", h.h_secsize); + printf("symbol size: %04x\n", h.h_symsize); + printf("option size: %04x\n", h.h_optsize); + printf("number sections: %04x\n", h.h_num_secs); + printf("number symbols: %04x\n", h.h_num_syms); + + // records [until record_eof] + + std::vector data; + data.resize(h.h_recsize); + ok = read(fd, data.data(), h.h_recsize); + if (ok != h.h_recsize) errx(EX_DATAERR, "%s truncated", name); + + + uint8_t op = REC_END; + uint32_t pc = 0; + + auto iter = data.begin(); + while (iter != data.end()) { + + op = read_8(iter); + if (op == 0) break; + if (op < 0xf0) { + iter += op; + pc += op; + printf("DATA: %02x\n", op); + continue; + } + + switch(op) { + + case REC_EXPR: + { + uint8_t bytes; + uint8_t op = 0; + bytes = read_8(iter); + + printf("EXPR: %02x : ", bytes); + pc += bytes; + + for(;;) { + op = read_8(iter); + if (op == OP_END) break; + switch (op) { + case OP_LOC: { + uint8_t section = read_8(iter); + uint32_t offset = read_32(iter); + if (section < sizeof(sections) / sizeof(sections[0])) + printf("%s+%04x ", sections[section], offset); + else + printf("section %02x+%04x ", section, offset); + } + break; + case OP_VAL: + printf("%04x ", read_32(iter)); + break; + case OP_SYM: + printf("symbol %02x ", read_16(iter)); + break; + case OP_SHR: printf(">> "); break; + case OP_SHL: printf("<< "); break; + default: + printf("\n"); + errx(EX_DATAERR, "%s: unknown expression opcode %02x", name, op); + + } + } + printf("\n"); + } + break; + + case REC_DEBUG: + { + + static const char *debugs[] = { + "D_C_FILE", + "D_C_LINE", + "D_C_SYM", + "D_C_STAG", + "D_C_ETAG", + "D_C_UTAG", + "D_C_MEMBER", + "D_C_EOS", + "D_C_FUNC", + "D_C_ENDFUNC", + "D_C_BLOCK", + "D_C_ENDBLOCK", + "D_LONGA_ON", + "D_LONGA_OFF", + "D_LONGI_ON", + "D_LONGI_OFF", + }; + + uint16_t size = read_16(iter); + printf("\t;DEBUG\n"); + + for (unsigned i = 0; i < size; ++i) { + uint8_t op = read_8(iter); + switch(op) { + case D_LONGA_ON: + printf("\tlonga\ton\n"); + break; + case D_LONGA_OFF: + printf("\tlonga\toff\n"); + break; + case D_LONGI_ON: + printf("\tlongi\ton\n"); + break; + case D_LONGI_OFF: + printf("\tlongi\toff\n"); + break; + case D_C_FILE: { + std::string s = read_cstring(iter); + uint16_t line = read_16(iter); + printf("\t.file\t\"%s\",%d\n", s.c_str(), line); + break; + } + case D_C_LINE: { + uint16_t line = read_16(iter); + printf("\t.line\t%d\n", line); + break; + } + case D_C_BLOCK: { + uint16_t block = read_16(iter); + printf("\t.block\t%d\n", block); + break; + } + case D_C_SYM: { + break; + } + + default: + errx(EX_DATAERR, "%s: unknown debug opcode %02x", name, op); + break; + + } + } + } + break; + + case REC_SECT: { + uint8_t section = read_8(iter); + printf("\t.sect\t%d\n", section); + break; + } + case REC_SPACE: + case REC_ORG: + case REC_RELEXP: + case REC_LINE: + default: + errx(EX_DATAERR, "%s: unknown opcode %02x", name, op); + } + } + + if (iter != data.end() || op != REC_END) errx(EX_DATAERR, "%s records ended early", name); + + + // section info + + data.resize(h.h_secsize); + ok = read(fd, data.data(), h.h_secsize); + if (ok != h.h_secsize) errx(EX_DATAERR, "%s truncated", name); + + printf("\nSections\n"); + + iter = data.begin(); + while (iter != data.end()) { + + + uint8_t number = read_8(iter); + uint8_t flags = read_8(iter); + uint32_t size = read_32(iter); + uint32_t org = read_32(iter); + + printf("section %d\n", number); + printf("flags: %02x ", flags); + +#undef _ +#define _(x) if (flags & x) fputs(#x " ", stdout) + _(SEC_OFFSET); + _(SEC_INDIRECT); + _(SEC_STACKED); + _(SEC_REF_ONLY); + _(SEC_CONST); + _(SEC_DIRECT); + _(SEC_NONAME); + fputs("\n", stdout); + + // todo -- section name -- cstring? + //assert(flags & SEC_NONAME); + std::string s; + if (!(flags & SEC_NONAME)) s = read_cstring(iter); + } + + + // symbol info + data.resize(h.h_symsize); + ok = read(fd, data.data(), h.h_symsize); + if (ok != h.h_symsize) errx(EX_DATAERR, "%s truncated", name); + + printf("\nSymbols\n"); + + iter = data.begin(); + while (iter != data.end()) { + uint8_t type = read_8(iter); + uint8_t flags = read_8(iter); + uint8_t section = read_8(iter); + uint32_t offset = type == S_UND ? 0 : read_32(iter); + std::string name = read_cstring(iter); + + printf("name: %s\n", name.c_str()); + printf("type: %02x %s\n", type, type < sizeof(types) / sizeof(types[0]) ? types[type] : ""); + printf("flags: %02x ", flags); +#undef _ +#define _(x) if (flags & x) fputs(#x " ", stdout) + _(SF_GBL); + _(SF_DEF); + _(SF_REF); + _(SF_VAR); + _(SF_PG0); + _(SF_TMP); + _(SF_DEF2); + _(SF_LIB); + fputs("\n", stdout); + printf("section: %02x %s\n", section, + section < sizeof(sections) / sizeof(sections[0]) ? sections[section] : ""); + if (type != S_UND) + printf("offset: %04x\n", offset); + + } + + +} + + + +void dump_lib(const char *name, int fd) +{ + Lib_head h; + ssize_t ok; + + ok = read(fd, &h, sizeof(h)); + if (ok != sizeof(h)) + errx(EX_DATAERR, "%s is not an object file", name); + + + le_to_host(h.l_magic); + le_to_host(h.l_version); + le_to_host(h.l_filtyp); + le_to_host(h.l_modstart); + le_to_host(h.l_numsyms); + le_to_host(h.l_symsize); + le_to_host(h.l_numfiles); + + assert(h.l_magic == MOD_MAGIC); + assert(h.l_version == 1); + assert(h.l_filtyp == 2); + + printf("modstart: %04x\n", h.l_modstart); + printf("number symbols: %04x\n", h.l_numsyms); + printf("number files: %04x\n", h.l_numfiles); + + printf("\n"); + std::vector data; + long count = h.l_modstart - sizeof(h); + if (count < 0) errx(EX_DATAERR, "%s", name); + data.reserve(count); + ok = read(fd, data.data(), count); + if (ok != count) errx(EX_DATAERR, "%s truncated", name); + + + // files + auto iter = data.begin(); + for (int i = 0; i < h.l_numfiles; ++i) { + uint16_t file_number = read_16(iter); + std::string s = read_pstring(iter); + printf("%02x %s\n", file_number, s.c_str()); + } + printf("\n"); + + // symbols + auto name_iter = iter + h.l_numsyms * 8; + for (int i = 0; i < h.l_numsyms; ++i) { + uint16_t name_offset = read_16(iter); + uint16_t file_number = read_16(iter); + uint32_t offset = read_32(iter); + std::string name = read_pstring(name_iter); + + printf("symbol: %04x %s\n", i, name.c_str()); + //printf("name offset: %02x\n", name_offset); + printf("file_number: %02x\n", file_number); + printf("module offset: %04x\n", offset); + } + printf("\n"); + + for (int i = 0; i < h.l_numfiles; ++i) { + dump_obj(name, fd); + } + + +} + +void dump(const char *name) { + Header h; + int fd; + ssize_t ok; + + fd = open(name, O_RDONLY); + if (fd < 0) err(EX_NOINPUT, "Unable to open %s", name); + + + ok = read(fd, &h, sizeof(h)); + if (ok != sizeof(h)) + errx(EX_DATAERR, "%s is not an object file", name); + + le_to_host(h.h_magic); + le_to_host(h.h_version); + le_to_host(h.h_filtyp); + + if (h.h_magic != MOD_MAGIC || h.h_version != 1 || h.h_filtyp > 2) + errx(EX_DATAERR, "%s is not an object file", name); + + lseek(fd, 0, SEEK_SET); + if (h.h_filtyp == 1) dump_obj(name, fd); + else dump_lib(name, fd); + + close(fd); +} + +int main(int argc, char **argv) { + + int c; + while ((c = getopt(argc, argv, "")) != -1) { + + } + + argv += optind; + argc -= optind; + + if (argc == 0) usage(); + + for (int i = 0; i < argc; ++i) { + dump(argv[i]); + } + + return 0; +} \ No newline at end of file diff --git a/obj816.h b/obj816.h new file mode 100644 index 0000000..9a68454 --- /dev/null +++ b/obj816.h @@ -0,0 +1,175 @@ +#include + +#pragma pack(push, 1) + +#define VERS " 3.01 " /* version number for programs */ +#define CDATE "1992-1997" /* copyright date for programs */ + +typedef struct Mod_head { + uint32_t h_magic; /* magic number for detection */ + uint16_t h_version; /* version number of object format */ + uint8_t h_filtyp; /* file type, object or library */ + uint8_t h_namlen; /* length of module name */ + uint32_t h_recsize; /* sizeof records section */ + uint16_t h_secsize; /* sizeof section section */ + uint32_t h_symsize; /* sizeof symbol section */ + uint16_t h_optsize; /* sizeof options section */ + uint8_t h_tot_secs; /* total number of sections in module */ + uint8_t h_num_secs; /* number of sections referenced */ + uint16_t h_num_syms; /* number of symbols */ +} Mod_head; + +typedef struct Lib_head { + uint32_t l_magic; /* magic number for detection */ + uint16_t l_version; /* version number of object format */ + uint8_t l_filtyp; /* file type, object or library */ + uint8_t l_unused1; + uint32_t l_modstart; /* offset of modules start */ + uint32_t l_numsyms; /* number of symbol entries */ + uint32_t l_symsize; /* sizeof symbol section */ + uint32_t l_numfiles; /* number of files */ +} Lib_head; + +#define MOD_CONVERT "lwbblslsbbw" +#define LIB_CONVERT "lwbbllll" + +#define MOD_REC_OFF(x) (sizeof(x)+x.h_namlen) +#define MOD_SEC_OFF(x) (MOD_REC_OFF(x)+x.h_recsize) +#define MOD_SYM_OFF(x) (MOD_SEC_OFF(x)+x.h_secsize) +#define MOD_OPT_OFF(x) (MOD_SYM_OFF(x)+x.h_symsize) +#define MOD_NEXT_OFF(x) (MOD_OPT_OFF(x)+x.h_optsize) + +#define MOD_MAGIC 0x5a44525a /* 'ZRDZ' */ +#define MOD_VERSION 1 +#define MOD_OBJECT 1 +#define MOD_LIBRARY 2 +#define MOD_OBJ68K 3 + +#define REC_END 0 +/* 1-xx are numbers of constant data bytes */ +#define REC_SECT 0xf0 /* next word is section number */ +#define REC_EXPR 0xf1 /* expression follows */ +#define REC_SPACE 0xf2 /* word count of bytes to reserve */ +#define REC_ORG 0xf3 /* long word new pc */ +#define REC_RELEXP 0xf4 /* pc-relative expression */ +#define REC_DEBUG 0xf5 /* debug info record */ +#define REC_LINE 0xf6 /* bump line counter */ + +enum { + OP_END=0, /* end of expression */ + OP_SYM, /* ref to extern symbol */ + OP_VAL, /* constant value */ + OP_LOC, /* ref to offset from start of section */ + + OP_UNA=10, + OP_NOT=10, + OP_NEG, + OP_FLP, + + OP_BIN=20, + OP_EXP=20, OP_MUL, OP_DIV, OP_MOD, OP_SHR, + OP_SHL, OP_ADD, OP_SUB, OP_AND, OP_OR, + OP_XOR, OP_EQ, OP_GT, OP_LT, OP_UGT, + OP_ULT, + OP_LAST +}; + +enum { S_UND, S_ABS, S_REL, S_EXP, S_REG, S_FREG }; /* symbol type */ +enum { ST_NOSIZE, ST_8BIT, ST_16BIT, ST_32BIT, + ST_FLOAT, ST_DOUBLE, ST_8051, ST_Z8, ST_DS, ST_EQU }; + +enum { + D_C_FILE=100, + D_C_LINE, + D_C_SYM, + D_C_STAG, + D_C_ETAG, + D_C_UTAG, + D_C_MEMBER, + D_C_EOS, + D_C_FUNC, + D_C_ENDFUNC, + D_C_BLOCK, + D_C_ENDBLOCK, + D_LONGA_ON, + D_LONGA_OFF, + D_LONGI_ON, + D_LONGI_OFF +}; + +/* used for generating source level debugging information */ + +enum { DT_NON, DT_PTR, DT_FCN, DT_ARY, DT_FPTR, DT_FFCN }; +enum { T_NULL, T_VOID, T_SCHAR, T_CHAR, T_SHORT, T_INT16, T_INT32, T_LONG, + T_FLOAT, T_DOUBLE, T_STRUCT, T_UNION, T_ENUM, T_LDOUBLE, + T_UCHAR, T_USHORT, T_UINT16, T_UINT32, T_ULONG }; +enum { C_NULL, C_AUTO, C_EXT, C_STAT, C_REG, C_EXTDEF, C_ARG, + C_STRTAG, C_MOS, C_EOS, C_UNTAG, C_MOU, C_ENTAG, C_MOE, + C_TPDEF, C_USTATIC, C_REGPARM, C_FIELD, C_UEXT, C_STATLAB, + C_EXTLAB, C_BLOCK, C_EBLOCK, C_FUNC, C_EFUNC, C_FILE, C_LINE, + C_FRAME }; + + +#define SF_GBL 0x01 /* label is global */ +#define SF_DEF 0x02 /* label is defined in this module */ +#define SF_REF 0x04 /* label is referenced in this module */ +#define SF_VAR 0x08 /* label is variable */ +#define SF_PG0 0x10 /* label is Page0 type */ +#define SF_TMP 0x20 /* label is temporary (LLCHAR) */ +#define SF_DEF2 0x40 /* label has been defined in pass 2 ( ZAS only ) */ +#define SF_LIB 0x40 /* label in library (used by ZLN) */ + +#define SEC_OFFSET 0x0001 +#define SEC_INDIRECT 0x0002 +#define SEC_STACKED 0x0004 +#define SEC_REF_ONLY 0x0008 +#define SEC_CONST 0x0010 +#define SEC_DIRECT 0x0020 +#define SEC_NONAME 0x0040 + + /* pre-defined sections */ +enum {SECT_PAGE0, SECT_CODE, SECT_KDATA, SECT_DATA, SECT_UDATA }; + +/* + Module format: + Module header + s: Module name (null terminated) + Records + Each record is in stack order terminated by REC_END + Section info + Section info format: --- for each section that has references + b: section number + b: section flags + l: size + l: org + s: name of section (only if SEC_NONAME not in flags) + Symbol info + Symbol info format: --- for each symbol + b: type + b: flags + b: section number + l: offset (only if type != S_UND) + s: name of symbol (null terminated) + + Library format: + Library header + File info - for each file + w: file number + b: file name len + c: file name (no null) + Symbol data - for each symbol + w: offset of name + w: file number + l: module offset - Hdr.l_modstart + Symbol names - for each symbol + b: length of name + c: symbol name (no null) + Modules - each module +*/ + + +/**************************************************/ +/* End of File OBJ816.H */ +/**************************************************/ + +#pragma pack(pop) diff --git a/wdclib.1 b/wdclib.1 new file mode 100644 index 0000000..806965e --- /dev/null +++ b/wdclib.1 @@ -0,0 +1,116 @@ +.Dd December 24, 2016 +.Dt WDCLIB 1 +.Os +.Sh NAME +.Nm wdclib +.Nd WDC Librarian +.Sh SYNOPSIS +.Nm +.Op Fl F Ar argfile +.Op Fl A | D | L | S | X +.Ar library +.Op Ar objfile ... +.Sh DESCRIPTION +.Nm +is a utility program that manipulates libraries of object modules. +.Nm +makes it possible to create a library of commonly used functions. This +library can be very efficiently searched and any modules required by the +program can be extracted from the library and placed in the output file. +.Pp +Since several object +modules may be contained in the same original source file, +.Nm +keeps track of the name of the file that each module comes from. +This allows all the modules associated with a file to be manipulated +without tediously typing in the name of each module. Options may be +specified individually or together. +.Sh OPTIONS +.Bl -tag -width indent +.It Fl A +This option tells +.Nm +to add the specified files to the library. The symbol dictionary is updated +to include the names of symbols defined in the object modules in the files. +If none of the options +.Fl A , D , +or +.Fl X +are given, the default is to assume option +.Fl A . +To create a library from a set of object files, use the command: +.Pp +.Dl WDCLIB -A MYLIB.LIB LIBSRC1.OBJ LIBSRC2.OBJ LIBSRC3.OBJ +.Pp +which will create a library file called +.Ar MYLIB.LIB +and add all the modules +from the three object files. If +.Ar MYLIB.LIB +already existed, the modules +from the three object files will be added to the library. +.It Fl D +The modules in the library that originally came from the named files are +deleted from the library. Modules must be deleted before being replaced +with new ones. +.Pp +The following example shows how to remove the modules associated with an +object file. +.Pp +.Dl WDCLIB -D MYLIB.LIB LIBSRC3.OBJ +.Pp +All of the modules associated with the file +.Ar LIBSRC3.OBJ +will be deleted from the library. +.Pp +This example shows how to replace a file in a library. +.Pp +.Dl WDCLIB -D MYLIB.LIB LIBSRC2.OBJ +.Dl WDCLIB -A MYLIB.LIB LIBSRC2.OBJ +.Pp +The modules associated with +.Ar LIBSRC2.OBJ +will first be deleted from the library and then added from the new version +of the file. The following options display information about the library +file after the modification arguments, if any, have been processed. +.It Fl F +This option must be followed by the name of a text file. The file will be +read and arguments will be extracted from the file. When the end of file +is reached, additional arguments are again extracted from the command +line. This allows more object modules than will fit on the standard command +line to be processed at one time. +.Pp +For example, these commands add all files with a +.Ar .OBJ +extension to the library. +.Pp +.Dl DIR *.OBJ > OBJLIST +.Dl WDCLIB -A MYLIB.LIB -F OBJLIST +.It Fl L +This option causes a list of the files in the library to be printed. +Associated with each file name is a file number. This number will also +appear in the symbol listing which indicates which file contains the +module that defines that symbol. This command will display the names +of all files added to a library. +.Pp +.Dl WDCLIB -L MYLIB.LIB +.Pp +This command adds two files to the library. +.Pp +.Dl WDCLIB -AL MYLIB.LIB LIBSRC1.OBJ LIBSRC2.OBJ +.Pp +After the files are added, a list of all the files in the library will +be printed. +.It Fl S +This option causes the dictionary of symbols contained in the library to +be printed. The dictionary is printed in alphabetical order. The number +of the file that defined the symbol along with the offset into the +library of the module that defined it are printed beside the symbol name. +.It Fl X +The modules in the library that originally came from the named files +are extracted from the library and placed into files with the same +name. After extraction, the modules in the library are deleted. +.Pp +The following example extracts two files from a library. +.Pp +.Dl WDCLIB -X MYLIB.LIB LIBSRC3.OBJ LIBSRC1.OBJ