This commit is contained in:
Kelvin Sherlock 2016-12-24 14:58:55 -05:00
commit 9055a46c62
3 changed files with 799 additions and 0 deletions

508
dumpobj.cpp Normal file
View File

@ -0,0 +1,508 @@
#include <string>
#include <err.h>
#include <unistd.h>
#include <sysexits.h>
#include <stdlib.h>
#include <fcntl.h>
#include <assert.h>
#include <stdio.h>
#include <type_traits>
#include <vector>
#include "obj816.h"
enum class endian {
little = __ORDER_LITTLE_ENDIAN__,
big = __ORDER_BIG_ENDIAN__,
native = __BYTE_ORDER__
};
template<class T>
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<class T>
void le_to_host(T &value) {
swap_if(value, std::integral_constant<bool, endian::native == endian::big>{});
}
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<class T>
uint8_t read_8(T &iter) {
uint8_t tmp = *iter;
++iter;
return tmp;
}
template<class T>
uint16_t read_16(T &iter) {
uint16_t tmp = 0;
tmp |= *iter << 0;
++iter;
tmp |= *iter << 8;
++iter;
return tmp;
}
template<class T>
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<class T>
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<class T>
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<char> 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<uint8_t> 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<uint8_t> 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;
}

175
obj816.h Normal file
View File

@ -0,0 +1,175 @@
#include <stdint.h>
#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)

116
wdclib.1 Normal file
View File

@ -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