Import GccFindHit and hunk2aout tools.

This commit is contained in:
Krystian Bacławski 2012-02-15 22:42:56 -08:00
parent de64a69ad4
commit 7851d27114
5 changed files with 1407 additions and 0 deletions

307
tools/GccFindHit.c Normal file
View File

@ -0,0 +1,307 @@
/* GccFindHit V1.2.1, 07/12/96
*
* The same than FindHit by Michael Sinz, but for GCC users
* Usage: GccFindHit <executable file> <list of offsets in hexadecimal>
* The file should have been linked with the '-g' flag passed to gcc
* to turn on debugging information (the 'stabs')
*
* GccFindHit outputs the line numbers matching with the offsets given by
* Enforcer (or whatever). Currently, there is no need
* to provide the hunk number because it should always be zero.
*
* Copyright (C) 1995 Daniel Verite -- daniel@brainstorm.eu.org
* This program is distributed under the General GNU Public License version 2
* See the file COPYING for information about the GPL
*
* v1.2.1, 07/12/96
* David Zaroski, cz253@cleveland.Freenet.Edu:
* o use BYTE_ORDER from system includes to get the host's endianness
*
* Daniel Verite, daniel@brainstorm.eu.org:
* o removed references to LITTLE_ENDIAN in Makefile.in
*
* v1.2, 30/12/95
*
* Daniel Verite, daniel@brainstorm.eu.org:
* o added handling of HUNK_NAME
* o fixed a small glitch in the strings seeks
*
* v1.1, 28/09/95
*
* Hans Verkuil, hans@wyst.hobby.nl:
* o GccFindHit no longer reads the strings into memory, but seek()s them
* instead, saving lots of memory.
* o added version string.
*
* v1.0, 22/05/95
*
* First release
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include "defs.h"
extern int errno;
int ExeFile,NbOffs;
unsigned long *SearchOffs;
static const char version_id[] = "\000$VER: GccFindHit 1.2.1 (07.12.96)";
int Read4 (long *buf)
{
if (read (ExeFile,buf,4)==4) {
*buf = GETLONG(*buf);
return 1;
}
else
return 0;
}
struct Header *ReadHeader ()
{
long nb,size;
struct Header *h;
int i;
/* skip hunk names */
while (Read4 (&size) && size)
lseek (ExeFile, size<<2, SEEK_CUR);
/* reads the number of hunks */
if (!Read4(&nb))
return NULL;
h = (struct Header*)malloc(sizeof(struct Header)+(nb-1)*sizeof(long));
if (!h)
return NULL;
h->nb_hunks = nb;
if (Read4 (&h->first) && Read4 (&h->last)) {
for (i=0; i<nb; i++)
if (!Read4 (&h->sizes[i])) {
free (h);
return NULL;
}
}
return h;
} /* ReadHeader() */
int long_cmp (long *e1,long *e2)
{
return (*e1)<(*e2);
}
void SkipRelocation ()
{
unsigned long no; /* number of offsets */
long h; /* hunk number */
while (Read4 (&no) && no && Read4 (&h))
lseek (ExeFile, no<<2, SEEK_CUR);
}
/* this function hasn't been tested; AFAIK, ld won't output short relocs,
so it's useless for now */
void SkipShortRel ()
{
unsigned long no;
short h;
while (Read4 (&no) && no && read (ExeFile, &h, sizeof h))
lseek (ExeFile, no<<1, SEEK_CUR);
}
/* can be slow if I/O buffering doesn't do some read-ahead */
void SkipSymbols ()
{
long nl; /* name length in long words */
while (Read4 (&nl) && nl) {
/* skips the name + the value */
lseek (ExeFile, (nl+1)<<2, SEEK_CUR);
}
}
/* skip hunks such as HUNK_NAME that have their size in the first long */
void SkipHunk ()
{
unsigned long size;
if (Read4 (&size))
lseek (ExeFile, size<<2, SEEK_CUR);
}
char *get_string(long offset)
{
static char buf[256];
lseek(ExeFile, offset, SEEK_SET);
read(ExeFile, buf, 255);
buf[255] = 0;
return buf;
}
void GetLines (long symsz, BSD_SYM *syms, long string_offset)
{
long nbsyms = symsz / sizeof(BSD_SYM);
BSD_SYM *sym = syms;
unsigned char prev_type;
long srcname = 0, prev_src = 0;
unsigned short prev_line = 0;
unsigned long offs , prev_offs = -1UL;
int i;
while (nbsyms--) {
switch (sym->type) {
case N_SO:
case N_SOL:
srcname = GETLONG (sym->strx);
break;
case N_SLINE:
offs = OFFSET_N_SLINE (GETLONG (sym->value));
for (i = 0; i < NbOffs; i++) {
if (SearchOffs[i] >= prev_offs && SearchOffs[i] < offs) {
printf ("%s: line %hd, offset 0x%lx\n",
get_string(prev_src + string_offset), prev_line,
prev_offs);
}
}
prev_offs = offs;
prev_line = GETWORD (sym->desc);
prev_src = srcname;
break;
}
prev_type = sym->type;
sym++;
}
/* the last SLINE is a special case */
for (i = 0; i < NbOffs; i++) {
if (SearchOffs[i] == prev_offs) {
printf ("%s: line %hd, offset 0x%lx\n",
get_string(prev_src + string_offset), prev_line,
prev_offs);
}
}
}
void HunkDebug (void)
{
long hunksz, symsz, strsz;
struct bsd_header hdr;
long pos, init_pos = lseek (ExeFile, 0, SEEK_CUR);
char *syms;
if (init_pos < 0)
return;
if (Read4(&hunksz) && read (ExeFile, &hdr, sizeof(hdr)) == sizeof(hdr)) {
if (GETLONG(hdr.magic)==ZMAGIC) {
/* seems to be gcc-compiled */
strsz = GETLONG (hdr.strsz);
symsz = GETLONG (hdr.symsz);
if (strsz + symsz != 0) {
syms = (char*)malloc (symsz);
if (syms) {
if (read (ExeFile, syms, symsz) == symsz) {
pos = lseek(ExeFile, strsz, SEEK_CUR);
if (pos > 0)
GetLines (symsz, (BSD_SYM*)syms, pos - strsz);
}
free (syms);
}
}
}
}
/* go to the end of the hunk whatever happened before */
lseek (ExeFile, init_pos+((hunksz+1)<<2), SEEK_SET);
}
void DoHunks (struct Header *h)
{
long hnum,size,nsec=0;
while (Read4 (&hnum)) {
switch (hnum) {
case HUNK_NAME:
SkipHunk ();
break;
case HUNK_CODE:
case HUNK_DATA:
if (Read4 (&size)) {
nsec++;
lseek (ExeFile, (size&0x3fffffff)<<2, SEEK_CUR);
}
break;
case HUNK_BSS:
nsec++;
Read4 (&size);
case HUNK_END:
case HUNK_BREAK:
break;
case HUNK_RELOC32:
case HUNK_RELOC16:
case HUNK_RELOC8:
case HUNK_DRELOC32:
case HUNK_DRELOC16:
case HUNK_DRELOC8:
SkipRelocation();
break;
case HUNK_RELOC32SHORT:
SkipShortRel ();
break;
case HUNK_SYMBOL:
SkipSymbols();
break;
case HUNK_DEBUG: /* here we are... */
HunkDebug ();
break;
default:
fprintf (stderr, "Unexpected hunk 0x%lx\n", hnum);
return;
}
}
} /* DoHunks() */
void Out(int code)
{
if (ExeFile>0) close (ExeFile);
if (SearchOffs) free (SearchOffs);
exit (code);
}
int main(int argc,char **argv)
{
long HunkNum;
struct Header *header=NULL;
int i;
if (argc<3) {
fprintf (stderr,"Usage: %s <file> <hex offsets>\n",argv[0]);
Out (1);
}
ExeFile = open (argv[1], O_RDONLY);
if (ExeFile<0) {
fprintf (stderr,"can't open %s:%s\n", argv[1], strerror (errno));
Out (1);
}
NbOffs = argc-2;
SearchOffs = (long*)malloc (sizeof (long)*NbOffs);
if (!SearchOffs) {
fprintf (stderr,"No memory\n");
Out (1);
}
for (i=0; i<NbOffs; i++) {
if (sscanf (argv[i+2],"%lx",&SearchOffs[i])!=1) {
fprintf (stderr, "Operand %s is not an hex offset\n", argv[i+2]);
Out (1);
}
}
if (!Read4(&HunkNum) || HunkNum!=HUNK_HEADER || !(header=ReadHeader())) {
fprintf (stderr, "%s is not an amigaos executable\n", argv[1]);
Out (1);
}
DoHunks (header);
free (header);
Out (0);
return 0; /* another brick in the -Wall */
} /* main() */

21
tools/GccFindHit.doc Normal file
View File

@ -0,0 +1,21 @@
README for GccFindHit V1.2, 25/05/95
This tool should be used in conjunction with Enforcer.
Its purpose is to find the source name/line corresponding to a given offset
in the executable. Very simple to use:
when your program named, say, 'prog', is a bad boy
and makes Enforcer hit(s), remember the offset(s) of the hit(s) displayed
by Enforcer and run the command 'GccFindHit prog <list of offsets in hex>'
The offsets are separated by blanks.
Enforcer gives also the hunk number, but it should always be zero.
If it's not and your program is compiled by gcc, please let me know
about it.
GccFindHit understands the stabs from the aout format encapsulated
in the debug hunk of the AmigaOS executable, so it will work as
long as ld outputs its debug information this way.
Source code is included and it is distributed under the GPL
See the file COPYING for details about the GPL. If it's not in
the archive, please contact the site/person/organization you got
this program from, and tell them it is *required*
Daniel Verite -- daniel@brainstorm.eu.org

9
tools/Makefile Normal file
View File

@ -0,0 +1,9 @@
CC = gcc
CFLAGS = -O2 -Wall -I../target/include
all: GccFindHit hunk2aout
GccFindHit.o: GccFindHit.c defs.h
hunk2aout.o: hunk2aout.c
clean: GccFindHit hunk2aout

79
tools/defs.h Normal file
View File

@ -0,0 +1,79 @@
/* defs.h -- this file is part of GccFindHit
* Copyright (C) 1995 Daniel Verite -- daniel@brainstorm.eu.org
* This program is distributed under the General GNU Public License version 2
* See the file COPYING for information about the GPL
*/
#if BYTE_ORDER==LITTLE_ENDIAN
/* reverse for endianness */
#define GETLONG(x) ((((((x)&0xff)<<8) | (((x)&0xff00)>>8))<<16) | \
(((((x)&0xff000000)>>8)&0x00ff0000) | \
((x)&0x00ff0000)<<8)>>16)
#define GETWORD(x) ((((x)&0xff)<<8) | ((((x)&0xff00)>>8)&0xff))
#else
#define GETLONG(x) (x)
#define GETWORD(x) (x)
#endif
#define ZMAGIC 0x10b /* demand-paged executable */
#define N_SO 0x64
#define N_SOL 0x84
#define N_SLINE 0x44
/* Converts an SLINE value to an offset in the text section.
This definition is OK for ld 1.8, currently used on the Amiga AFAIK,
but you may change that for another linker */
#define OFFSET_N_SLINE(x) (x)
enum {
HUNK_UNIT=0x3e7,
HUNK_NAME,
HUNK_CODE,
HUNK_DATA,
HUNK_BSS,
HUNK_RELOC32,
HUNK_RELOC16,
HUNK_RELOC8,
HUNK_EXT,
HUNK_SYMBOL,
HUNK_DEBUG,
HUNK_END,
HUNK_HEADER,
HUNK_3F4, /* ? */
HUNK_OVERLAY,
HUNK_BREAK,
HUNK_DRELOC32,
HUNK_DRELOC16,
HUNK_DRELOC8,
HUNK_3FA, /* ? */
HUNK_LIB,
/* AmigaOS Manual 3rd ed. takes 0x3fc for both HUNK_INDEX and
HUNK_RELOC32SHORT. I don't know if it's an error or something;
anyway, there shouldn't be HUNK_INDEX in executable files, so
let's take the other one */
HUNK_RELOC32SHORT
};
/* amigaos hunk header structure */
struct Header {
long nb_hunks;
long first;
long last;
long sizes[1];
};
/* bsd header structure */
struct bsd_header{
long magic;
long symsz;
long strsz;
};
typedef struct {
long strx;
unsigned char type;
unsigned char other;
unsigned short desc;
long value;
} BSD_SYM;

991
tools/hunk2aout.c Normal file
View File

@ -0,0 +1,991 @@
;/* how to compile this thingy:
gcc2 -O2 -msmall-code -resident hunk2aout.c -o hunk2aout -DNDEBUG
quit
*/
/*
* Convert amiga object files in the hunk format into a.out-object files.
* ALINK style (ie. concatenated) libraries are supported as well, in that
* case a collection of object files is generated, you'll have to run
* `ar rs libfoo.a obj.*' on them to make an a.out-style library out of
* them.
*
* Currently untested are:
* o base-relative relocs and references
* I'll first have to teach gnu-ld how to deal with them ;-)
* o conversion of load files...
* o common symbols, amiga objects normally don't use them, sigh
*
* Currently not implemented are:
* o BLINK style indexed libraries (HUNK_LIB and HUNK_INDEX). If you're
* generating such libraries yourself, you can as well generate oldstyle
* libraries, and the libraries from Commodore-Amiga are in ALINK format
* (amiga.lib and friends).
* This index-format is so weird and complicated that I didn't bother
* long to decide not to support it. If someone volunteers (you got
* the source;-)) please send me enhancements!
*
* V1.0 91-10-08 M.Wild first hack
* V1.1 91-10-19 M.Wild add support for CHIP hunk attribute in
* DATA/BSS hunks (not CODE, ever used??)
* Now, when are multiple hunks supported ? ;-)
* V2.0 97-03-01 fnf Change name to hunk2aout, apply patch from
* Hans Verkuil, use standard AmigaOS versioning.
*
* This is free software. This means that I don't care what you do with it
* as long as you don't claim you wrote it. If you enhance it, please
* send me your diffs!
* Oh, of course, you use this stuff entirely at your own risk, I'm not
* responsible for any damage this program might cause to you, your computer,
* your data, your cat, your whateveryoucanthinkof, no warranty whatsoever is
* granted.
*
* I can be reached on internet as: wild@nessie.cs.id.ethz.ch (Markus Wild)
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <a.out.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
/* This is really <dos/doshunks.h>, which is a 2.0 header file.
* You can get those 2.0 headers from CATS.
* Sorry, I'm not allowed to include them here. You may as well take the
* AmigaDOS Manual 2nd ed. (you'll miss the a4-rel hunks) or 3rd ed. and write
* the header yourself, it's not that long and difficult
*/
#include <dos/doshunks.h>
/* strangely enough, this is missing from the doshunks.h file */
#define HUNK_ATTRIBUTE(h) ((h) >> 30)
#define HUNK_VALUE(h) ((h) & 0x3fffffff)
#define HUNK_ATTR_CHIP 0x01
/* These are the symbol names we are generating to denote the limit between
* the `normal' and `chip' data/bss.
*/
#define CHIP_DATA_START "__chip_data"
#define CHIP_BSS_START "__chip_bss"
#ifndef NDEBUG
#define DP(a) printf a
#else
#define DP(a)
#endif
static char *version_tag = "\0$VER: hunk2aout 2.0 (1.3.97)\r\n";
extern int errno;
/* my favorite typedefs ;-)) */
typedef unsigned char uchar;
typedef unsigned long ulong;
ulong *file_buf = 0;
/* if set no progress reports are output */
int silent_mode = 0;
struct reloc {
/* at which offset to relocate */
int offset;
/* based on which hunk base */
int from_hunk, to_hunk;
int size;
int pcrel;
int baserel;
/* if != -1, the "to_hunk" field is not used */
int sym_num;
};
/* NOTE: this symbol definition is compatible with struct nlist, and it will
* be converted into a struct nlist in 'emit_aout_obj' */
struct symbol {
int name; /* string as offset into string table */
uchar type;
uchar pad1; /* really n_other */
short hunk_num; /* really n_desc */
ulong value;
};
struct table {
void *base;
int el_size;
int i;
int max_el;
};
void
emit_aout_file (int fd, void *text, void *data, void *chip_data,
struct exec *hdr, int chip_data_size, int chip_bss_size,
struct table *ch_tab, struct table *dh_tab, struct table *bh_tab,
struct table *cdh_tab, struct table *cbh_tab,
struct table *reloc_tab, struct table *symbol_tab, int max_hunk);
#define TAB_START_SIZE 1024
/* advance the hunk-pointer to the next hunk. Assumes the hunk-pointer is
* pointing at the length-field currently
*/
static void inline
next_hunk(ulong **hp)
{
/* skip over the length field and the there given length */
*hp += 1 + **hp;
}
/* save a lot of space for duplicate string, that all say "only.. with size.. */
static void inline
limit_hunk (char *hunk_name)
{
fprintf (stderr, "only one %s hunk with size!=0 supported.\n", hunk_name);
}
/****************************************************************************/
/* these two function maintain the string table. You may only free the last
* string allocated. (This could be done with an obstack as well, but I really
* don't need the whole functionality of an obstack, so I kept it simple ;-))
* Only use the offset, since the table itself may be reallocated.
*/
char *str_table = 0;
int strtab_size, strtab_index;
static int inline
stralloc (int len)
{
int res;
/* always include the zero terminator */
len++;
if (! str_table)
{
strtab_size = TAB_START_SIZE;
/* start the table at index 4, leaving space to later fill in the
* size of the table */
strtab_index = 4;
str_table = malloc (strtab_size);
}
while (strtab_index + len > strtab_size)
{
strtab_size <<= 1;
str_table = realloc (str_table, strtab_size);
}
res = strtab_index;
strtab_index += len;
return res;
}
static void inline
strfree (int str)
{
strtab_index = str;
}
/****************************************************************************/
static void inline
add_table (struct table *tab, void *el)
{
if (tab->i == tab->max_el)
{
if (! tab->base)
{
tab->max_el = TAB_START_SIZE;
tab->base = malloc (tab->max_el * tab->el_size);
}
else
{
tab->max_el <<= 1;
tab->base = realloc (tab->base, tab->max_el * tab->el_size);
}
if (! tab->base)
{
fprintf (stderr, "Out of memory adding to table.\n");
/* exit does close all outstanding files ;-) */
exit (20);
}
}
bcopy (el, (uchar *)tab->base + (tab->i++ * tab->el_size), tab->el_size);
}
static void inline
add_reloc (struct table *tab, int from, int to, int offset,
int size, int pcrel, int baserel, int sym_num)
{
struct reloc r;
DP(("reloc: from=%d, to=%d, off=%d, size=%d, pc=%d, ba=%d, syn=%d\n",
from, to, offset, size, pcrel, baserel, sym_num));
r.from_hunk = from;
r.to_hunk = to;
r.offset = offset;
r.size = size;
r.pcrel = pcrel;
r.baserel = baserel;
r.sym_num = sym_num;
add_table (tab, &r);
}
static void inline
add_symbol (struct table *tab, int num, ulong type, int value, char *name)
{
struct symbol s;
s.hunk_num = num;
s.type = type >> 24;
s.value = value;
s.name = stralloc ((type & 0xffffff)<<2);
bcopy (name, str_table+s.name, (type & 0xffffff)<<2);
(str_table+s.name)[(type & 0xffffff)<<2] = 0;
/* some (really stupid..) compilers mention symbols twice, once as
* a definition, and once as an EXT_SYMB. So we really have to search
* the symbol_table before adding an EXT_SYMB and check if a symbol of this name
* isn't already defined for this value. If this hack should slow down
* the conversion dramatically, I'll have to resort to hashing, I don't
* like that idea... */
if (s.type == EXT_SYMB)
{
int i;
for (i = 0; i < tab->i; i++)
/* we have CSE in the compiler, right? ;-)) */
if (((struct symbol *)tab->base)[i].value == s.value &&
((struct symbol *)tab->base)[i].hunk_num == s.hunk_num &&
! strcmp (str_table+((struct symbol *)tab->base)[i].name,
str_table+s.name))
{
strfree (s.name);
return;
}
}
add_table (tab, &s);
}
/****************************************************************************/
void
digest_objfile (ulong **file_pptr, ulong *max_fp)
{
/* this makes it less clumsy.. */
ulong *file_ptr = *file_pptr;
static int obj_file_num = 0;
int units = 0;
int fd = -1;
/* if processed hunk has a CHIP attribute */
int is_chip;
/* buffer-pointers, where text & data sections are stored.
* Currently only one hunk with size!=0 of type text/data/bss each is
* supported.
* There is now an additional buffer to support one chip hunk as well.
* (chip-bss is supported too, but doesn't need a buffer ;-))
*/
uchar *text, *data, *chip_data;
ulong chip_data_size, chip_bss_size;
struct exec hdr;
/* hunk numbers, needed to associate reloc blocks with segments */
int hunk_num;
static struct table code_hunks = { 0, 4, 0, 0 };
static struct table data_hunks = { 0, 4, 0, 0 };
static struct table bss_hunks = { 0, 4, 0, 0 };
static struct table chip_data_hunks = { 0, 4, 0, 0 };
static struct table chip_bss_hunks = { 0, 4, 0, 0 };
/* static so that no initialization code is required */
static struct table reloc_tab = { 0, sizeof (struct reloc), 0, 0 };
static struct table symbol_tab = { 0, sizeof (struct symbol), 0, 0 };
/* (re) init tables */
strtab_index = 4;
code_hunks.i =
data_hunks.i =
bss_hunks.i =
chip_data_hunks.i =
reloc_tab.i =
symbol_tab.i = 0;
while (units < 2)
{
switch (HUNK_VALUE(*file_ptr++))
{
case HUNK_UNIT:
DP(("HUNK_UNIT: units = %d\n", units));
if (units++) break;
#if 0
if (! file_ptr[0])
#endif
{
/* need [], not *, so that gcc allocates a fresh copy for
* mkstemp() to modify! */
char tmp_nam[] = "obj.YYYY.XXXXXX";
/* this trick makes mkstemp() lots faster ;-) */
sprintf (tmp_nam, "obj.%04d.XXXXXX", obj_file_num++);
if ((fd = mkstemp (tmp_nam)) < 0)
fprintf (stderr, "Can't create %s (%s). Ignoring it.\n",
tmp_nam, strerror (errno));
}
#if 0
/* this idea was too good.. there are so many stupid (and duplicate!) names
* of program units, that this generated ridiculous results... */
else
{
char *file_name;
file_name = alloca (file_ptr[0] + 1);
strncpy (file_name, (char *)&file_ptr[1], file_ptr[0]);
if ((fd = open (file_name, O_RDWR|O_CREAT|O_EXCL, 0666)) < 0)
fprintf (stderr, "Can't create %s: %s. Ignoring it.\n",
file_name, strerror (errno));
}
#endif
/* init data for new object file */
text = data = chip_data = 0;
bzero (&hdr, sizeof (hdr));
chip_data_size = chip_bss_size = 0;
/* if someone want's to use'em on a sun, why shouldn't we make
* the files sun-conformant? */
hdr.a_mid = MID_SUN010;
hdr.a_magic = OMAGIC;
hunk_num = 0;
next_hunk (& file_ptr);
if (! silent_mode)
{
putchar ('.');
fflush (stdout);
}
break;
case HUNK_NAME:
case HUNK_DEBUG:
DP(("HUNK_NAME/DEBUG\n"));
/* this hunk is silently ignored ;-) */
next_hunk (& file_ptr);
break;
case HUNK_OVERLAY:
fprintf (stderr, "warning: overlay hunk ignored!\n");
next_hunk (& file_ptr);
break;
case HUNK_BREAK:
fprintf (stderr, "warning: break hunk ignored!\n");
break;
case HUNK_HEADER:
fprintf (stderr, "warning: load file header encountered.\n");
fprintf (stderr, " are you sure this is an object file?\n");
/* nevertheless, we go on. perhaps some day I need this feature to
* be able to convert a loadfile into an object file?! */
/* skip (never used) resident library names */
while (file_ptr[0]) next_hunk (& file_ptr);
/* skip null-word, table_size, F & L, and size-table */
file_ptr += 4 + (file_ptr[1] - file_ptr[2] + 1);
break;
case HUNK_CODE:
DP(("HUNK_CODE, size = $%x\n", file_ptr[0] << 2));
is_chip = HUNK_ATTRIBUTE(file_ptr[-1]) == HUNK_ATTR_CHIP;
if (is_chip)
fprintf (stderr, "CHIP code hunks are not supported, "
"ignoring CHIP attribute\n");
if (file_ptr[0])
{
/* only accept one code hunk with size != 0 */
if (hdr.a_text)
limit_hunk ("code");
else
{
text = (uchar *)&file_ptr[1];
hdr.a_text = file_ptr[0] << 2;
}
}
next_hunk (& file_ptr);
add_table (& code_hunks, &hunk_num);
hunk_num++;
break;
case HUNK_DATA:
DP(("HUNK_DATA, size = $%x\n", file_ptr[0] << 2));
is_chip = HUNK_ATTRIBUTE(file_ptr[-1]) == HUNK_ATTR_CHIP;
if (file_ptr[0])
{
/* only accept one data hunk with size != 0 */
if (is_chip)
{
if (chip_data_size)
limit_hunk ("chip data");
else
{
chip_data = (uchar *) &file_ptr[1];
chip_data_size = file_ptr[0] << 2;
}
}
else
{
if (hdr.a_data)
limit_hunk ("data");
else
{
data = (uchar *)&file_ptr[1];
hdr.a_data = file_ptr[0] << 2;
}
}
}
next_hunk (& file_ptr);
add_table (is_chip ? & chip_data_hunks : & data_hunks, & hunk_num);
hunk_num++;
break;
case HUNK_BSS:
DP(("HUNK_BSS, size = $%x\n", file_ptr[0] << 2));
is_chip = HUNK_ATTRIBUTE(file_ptr[-1]) == HUNK_ATTR_CHIP;
if (file_ptr[0])
{
/* only accept one bss hunk with size != 0 */
if (is_chip)
{
if (chip_bss_size)
limit_hunk ("chip bss");
else
chip_bss_size = file_ptr[0] << 2;
}
else
{
if (hdr.a_bss)
limit_hunk ("bss");
else
hdr.a_bss = file_ptr[0] << 2;
}
}
file_ptr++;
add_table (is_chip ? & chip_bss_hunks : & bss_hunks, & hunk_num);
hunk_num++;
break;
case HUNK_RELOC8:
case HUNK_RELOC16:
case HUNK_RELOC32:
/* do they work like this? don't know... */
case HUNK_DREL8:
case HUNK_DREL16:
case HUNK_DREL32:
{
int size, brel;
brel = file_ptr[-1] >= HUNK_DREL32;
size = (brel ? HUNK_DREL8 : HUNK_RELOC8) - file_ptr[-1];
DP(("HUNK_RELOC/DREL ($%x), brel = %d, size = %d\n", file_ptr[-1], brel, size));
while (file_ptr[0])
{
long to_reloc = file_ptr[1];
long n = file_ptr[0];
while (n--)
/* amiga relocs are automatically pcrel, when size < 2
* according to the AmigaDOS-Manual 2nd ed. */
add_reloc (&reloc_tab, hunk_num-1, to_reloc, file_ptr[n+2],
size, size != 2, brel, -1);
file_ptr += file_ptr[0] + 2;
}
}
file_ptr++;
break;
case HUNK_SYMBOL:
case HUNK_EXT:
DP(("HUNK_SYMBOL/EXT\n"));
while (file_ptr[0])
{
int n, size, brel;
DP((" EXT_: %d, %-*.*s\n", file_ptr[0] >> 24,
4*(file_ptr[0] & 0xffffff), 4*(file_ptr[0] & 0xffffff), &file_ptr[1]));
switch (file_ptr[0] >> 24)
{
case EXT_SYMB:
case EXT_DEF:
case EXT_ABS:
case EXT_RES:
add_symbol (&symbol_tab, hunk_num-1, file_ptr[0],
file_ptr[1+(file_ptr[0] & 0xffffff)],
(char *)&file_ptr[1]);
file_ptr += 2+(file_ptr[0] & 0xffffff);
break;
case EXT_COMMON:
/* first define the common symbol, then add the relocs */
add_symbol (&symbol_tab, hunk_num-1, file_ptr[0],
file_ptr[1+(file_ptr[0] & 0xffffff)],
(char *)&file_ptr[1]);
file_ptr += 2+(file_ptr[0] & 0xffffff);
/* now the references, translated into relocs */
for (n = file_ptr[0]; n--; )
add_reloc (&reloc_tab, hunk_num - 1, -1, file_ptr[n],
2, 0, 0, symbol_tab.i - 1);
next_hunk (&file_ptr);
break;
case EXT_REF8:
case EXT_REF16:
case EXT_REF32:
case EXT_DEXT8:
case EXT_DEXT16:
case EXT_DEXT32:
size = file_ptr[0] >> 24;
brel = size >= EXT_DEXT32;
size = (size == EXT_REF32 || size == EXT_DEXT32) ? 2 :
((size == EXT_REF16 || size == EXT_DEXT16) ? 1 : 0);
/* first define the symbol (as undefined ;-)),
* then add the relocs */
add_symbol (&symbol_tab, hunk_num-1, file_ptr[0],
0, (char *)&file_ptr[1]);
file_ptr += 1+(file_ptr[0] & 0xffffff);
/* now the references, translated into relocs */
for (n = file_ptr[0]; n; n--)
add_reloc (&reloc_tab, hunk_num - 1, -1, file_ptr[n],
size, size < 2, brel, symbol_tab.i - 1);
next_hunk (&file_ptr);
break;
default:
fprintf (stderr,
"Unknown symbol type %d, don't know how to handle!\n",
file_ptr[0] >> 24);
/* can't continue, don't know how much to advance the file_ptr
* to reach the next valid hunk/block */
exit(20);
}
}
file_ptr++;
break;
case HUNK_END:
DP(("HUNK_END\n"));
break;
case HUNK_LIB:
case HUNK_INDEX:
fprintf (stderr, "Convert this library into ALINK (join type) format.\n");
exit (20);
default:
fprintf (stderr, "Unknown hunk type $%x, unit offset = $%x.\n",
file_ptr[-1], ((file_ptr-1)-*file_pptr) * 2);
/* can't continue, don't know how much to advance the file_ptr
* to reach the next valid hunk/block */
exit(20);
}
if (file_ptr >= max_fp) break;
}
*file_pptr = file_ptr >= max_fp ? max_fp : file_ptr-1;
if (fd != -1)
emit_aout_file (fd, text, data, chip_data,
& hdr, chip_data_size, chip_bss_size,
& code_hunks, & data_hunks, & bss_hunks,
& chip_data_hunks, & chip_bss_hunks,
& reloc_tab, & symbol_tab, hunk_num);
}
void
emit_aout_file (int fd, void *text, void *data, void *chip_data,
struct exec *hdr, int chip_data_size, int chip_bss_size,
struct table *ch_tab, struct table *dh_tab, struct table *bh_tab,
struct table *cdh_tab, struct table *cbh_tab,
struct table *reloc_tab, struct table *symbol_tab, int max_hunk)
{
int *code_hunks = ch_tab->base;
int *data_hunks = dh_tab->base;
int *bss_hunks = bh_tab->base;
int *chip_data_hunks = cdh_tab->base;
int *chip_bss_hunks = cbh_tab->base;
char htype[max_hunk];
int i;
struct reloc *r;
struct symbol *s;
static struct table text_relocs = { 0, sizeof (struct relocation_info), 0, 0 };
static struct table data_relocs = { 0, sizeof (struct relocation_info), 0, 0 };
text_relocs.i =
data_relocs.i = 0;
/* convert hunk-numbers into N_TEXT,N_DATA,N_BSS types
* I temporarily use N_EXT to really mean `N_CHIP'
*/
for (i = 0; i < ch_tab->i; i++) htype[code_hunks[i]] = N_TEXT;
for (i = 0; i < dh_tab->i; i++) htype[data_hunks[i]] = N_DATA;
for (i = 0; i < bh_tab->i; i++) htype[bss_hunks[i]] = N_BSS;
for (i = 0; i < cdh_tab->i; i++) htype[chip_data_hunks[i]] = N_DATA|N_EXT;
for (i = 0; i < cbh_tab->i; i++) htype[chip_bss_hunks[i]] = N_BSS|N_EXT;
#ifndef NDEBUG
for (i = 0; i < max_hunk; i++) DP(("htype[%d] = %d\n", i, htype[i]));
#endif
/* first conversion run. Change all hunk-numbers into N_TEXT, N_DATA and
* N_BSS rsp.
* (If you wanted to support multi-hunk files (ie. files with more than
* one code/data/bss hunk with size > 0) you'd want to do the necessary
* conversions here.)
* A less general solution is currently implemented: one chip data and one
* chip bss hunk are supported as well. Multiple hunks should work analogous,
* but with tables instead of variables like `chip_data_size' and `data'.
*/
for (i = 0, r = (struct reloc *)reloc_tab->base; i < reloc_tab->i; i++, r++)
{
/* have to convert the destination hunk before the source hunk, since I
* need the information, whether I have to change a data or a chip data
* source. */
/* Convert the destination hunk, if this is a local reloc. If it has
* an associated symbol, that symbol will be converted from CHIP to whatever
* is needed
* If the target lies in a chip hunk, we have to change the offset in the
* source hunk to include the `hunk-gap' between source and target
*/
if (r->to_hunk > -1)
{
/* the base address of the used source hunk */
void *base_hunk;
/* this is the mentioned hunk-gap */
ulong offset;
switch (htype[r->from_hunk])
{
case N_TEXT:
base_hunk = text;
break;
case N_DATA:
base_hunk = data;
break;
case N_DATA|N_EXT:
base_hunk = chip_data;
break;
default:
fprintf (stderr, "Local reloc from illegal hunk ($%x)!\n",
htype[r->from_hunk]);
break;
}
/* account for an eventual shift of the former N_BSS space by
* chip_data_size bytes */
switch (htype[r->to_hunk])
{
/* those don't need a shift */
case N_TEXT:
case N_DATA:
offset = 0;
break;
case N_BSS:
offset = chip_data_size;
break;
case N_DATA|N_EXT:
offset = hdr->a_data;
break;
case N_BSS|N_EXT:
offset = chip_data_size + hdr->a_bss;
break;
}
DP(("r->from = %d, r->to = %d, base = %d, offset = %d\n", r->from_hunk, r->to_hunk, htype[r->from_hunk], offset));
/* I really don't know how much sense non-long relocs make here,
* but it's easy to support, so .. ;-) */
switch (r->size)
{
case 2:
*(long *)(base_hunk + r->offset) += (long)offset;
break;
case 1:
*(short *)(base_hunk + r->offset) += (short)offset;
break;
case 0:
*(char *)(base_hunk + r->offset) += (char)offset;
break;
}
r->to_hunk = htype[r->to_hunk] & ~N_EXT;
}
/* if it's a CHIP hunk, I have to increment the relocation address by
* the size of the base hunk */
if (htype[r->from_hunk] & N_EXT)
{
/* only N_DATA should come here, since there is no such thing as a
* reloc originating from BSS space, but we nevertheless check for it.. */
if (htype[r->from_hunk] == (N_DATA|N_EXT))
r->offset += hdr->a_data;
else
fprintf (stderr, "Reloc from CHIP-BSS space, undefined!!\n");
}
r->from_hunk = htype[r->from_hunk] & ~N_EXT;
}
/* now convert the symbols into nlist's */
for (i = 0, s = (struct symbol *)symbol_tab->base; i < symbol_tab->i; i++, s++)
{
int nl_type = 0;
/* change hunk numbers into types */
s->hunk_num = htype[s->hunk_num];
switch (s->type)
{
case EXT_DEF:
/* externally visible symbol */
nl_type = N_EXT;
/* fall into */
case EXT_SYMB:
nl_type |= s->hunk_num & ~N_EXT;
/* adjust multi-hunk values to the one-seg model */
if (s->hunk_num == N_DATA)
s->value += hdr->a_text;
else if (s->hunk_num == N_BSS)
s->value += hdr->a_text + hdr->a_data + chip_data_size;
else if (s->hunk_num == (N_DATA|N_EXT))
s->value += hdr->a_text + hdr->a_data;
else if (s->hunk_num == (N_BSS|N_EXT))
s->value += hdr->a_text + hdr->a_data + chip_data_size + hdr->a_bss;
break;
case EXT_ABS:
nl_type = N_ABS | N_EXT;
break;
case EXT_COMMON:
/* ok for common as well, because the value field is only setup
* for common-symbols */
case EXT_REF32:
case EXT_REF16:
case EXT_REF8:
case EXT_DEXT32:
case EXT_DEXT16:
case EXT_DEXT8:
nl_type = N_UNDF | N_EXT;
break;
default:
fprintf (stderr, "What kind of symbol is THAT? (%d)\n", s->type);
break;
}
s->type = nl_type;
s->pad1 = s->hunk_num = 0; /* clear nl_other & nl_desc fields */
}
/* now convert the reloc table. Adjust (like above) data/bss values to the
* one-segment model for local relocations */
for (i = 0, r = (struct reloc *)reloc_tab->base; i < reloc_tab->i; i++, r++)
{
struct relocation_info rel;
uchar *core_addr;
ulong delta;
memset(&rel, 0, sizeof(rel));
rel.r_address = r->offset;
core_addr = (r->from_hunk == N_TEXT) ? text :
((r->offset < hdr->a_data) ? data : chip_data);
/* r->offset has already been corrected to point at the chip data part
* appended to the data part. Since we don't physically join these
* segments (we just write them out after each other) we have to
* ignore these changes for patches, this is what DELTA is used for. */
delta = (core_addr == chip_data) ? hdr->a_data : 0;
DP(("r_add = $%x, core = %s, delta = %d, ", rel.r_address,
(core_addr == text) ? "text" : ((core_addr == data) ? "data" : "chip_data"),delta));
if (r->to_hunk == N_DATA)
if (r->size == 2)
*(ulong *)(core_addr + rel.r_address - delta) += hdr->a_text;
else
fprintf (stderr, "%s reloc into N_DATA, what should I do?\n",
r->size == 1 ? "Short" : "Byte");
else if (r->to_hunk == N_BSS)
if (r->size == 2)
*(ulong *)(core_addr + rel.r_address - delta) += hdr->a_text + hdr->a_data;
else
fprintf (stderr, "%s reloc into N_BSS, what should I do?\n",
r->size == 1 ? "Short" : "Byte");
#if 0
/* don't know, what went wrong, but this conversion surely converts
* _LVO calls wrong. I'm sure leaving this out will generate other bugs..
* sigh... */
/* hmm... amigadog-hunks seem to do this in a strange way...
* Those relocs *are* treated as pcrel relocs by the linker (blink),
* but they're not setup as such... geez, this hunk format.. */
if (r->pcrel)
switch (r->size)
{
case 2:
*(long *)(core_addr + rel.r_address - delta) -= rel.r_address;
break;
case 1:
*(short *)(core_addr + rel.r_address - delta) -= (short)rel.r_address;
break;
case 0:
*(char *)(core_addr + rel.r_address - delta) -= (char)rel.r_address;
break;
}
#endif
rel.r_symbolnum = r->sym_num > -1 ? r->sym_num : r->to_hunk;
rel.r_pcrel = r->pcrel;
rel.r_length = r->size;
rel.r_extern = r->sym_num > -1;
rel.r_baserel = r->baserel;
rel.r_jmptable = /* rel.r_relative = */ 0;
DP(("r68: %s reloc\n", (r->from_hunk == N_TEXT) ? "text" : "data"));
add_table ((r->from_hunk == N_TEXT) ? & text_relocs : & data_relocs,
&rel);
}
DP(("r68: #tr = %d, #dr = %d\n", text_relocs.i, data_relocs.i));
/* depending on whether we had any actual CHIP data, we have to adjust
* some of the header data, and we have to generate symbols containing the
* real size of the non-chip section(s) */
if (chip_data_size)
{
/* slightly different syntax, now that we directly add an nlist symbol */
add_symbol (symbol_tab, 0, (N_ABS << 24) | ((sizeof (CHIP_DATA_START)+3)>>2),
hdr->a_data, CHIP_DATA_START);
hdr->a_data += chip_data_size;
}
if (chip_bss_size)
{
add_symbol (symbol_tab, 0, (N_ABS << 24) | ((sizeof (CHIP_BSS_START)+3)>>2),
hdr->a_bss, CHIP_BSS_START);
hdr->a_bss += chip_bss_size;
}
/* oky, fill out the rest of the header and dump everything */
hdr->a_syms = symbol_tab->i * sizeof (struct nlist);
hdr->a_trsize = text_relocs.i * sizeof (struct relocation_info);
hdr->a_drsize = data_relocs.i * sizeof (struct relocation_info);
*(ulong *)str_table = strtab_index;
write (fd, (char *)hdr, sizeof (*hdr));
if (hdr->a_text) write (fd, text, hdr->a_text);
if (hdr->a_data - chip_data_size > 0)
write (fd, data, hdr->a_data - chip_data_size);
if (chip_data_size) write (fd, chip_data, chip_data_size);
if (hdr->a_trsize) write (fd, text_relocs.base, hdr->a_trsize);
if (hdr->a_drsize) write (fd, data_relocs.base, hdr->a_drsize);
if (hdr->a_syms) write (fd, symbol_tab->base, hdr->a_syms);
write (fd, str_table, strtab_index);
close (fd);
}
int
main (int argc, char *argv[])
{
struct stat stb;
int ret_val = 0;
ulong *obj_pointer;
FILE *fp;
/* loop over all arguments. Can be either
* o object files
* o libraries (ALINK style for now)
*/
while (*++argv)
{
if (! strcmp (*argv, "-s"))
{
silent_mode = 1;
continue;
}
if (stat (*argv, &stb) == -1)
{
fprintf (stderr, "%s: %s\n", *argv, strerror (errno));
continue;
}
file_buf = file_buf ? realloc (file_buf, stb.st_size)
: malloc (stb.st_size);
if (! file_buf)
{
fprintf (stderr, "%s: can't allocate %d byte of memory.\n",
*argv, stb.st_size);
ret_val = 20;
break;
}
if (!(fp = fopen (*argv, "r")))
{
fprintf (stderr, "Can't open %s: %s.\n", *argv, strerror (errno));
continue;
}
/* read the file in at once */
if (fread (file_buf, stb.st_size, 1, fp) != 1)
{
fprintf (stderr, "Can't read %s: %s.\n", *argv, strerror (errno));
fclose (fp);
continue;
}
if (! silent_mode)
printf ("Converting %s:\n", *argv);
/* oky, now digest the file (possibly more than one object file) */
for (obj_pointer = file_buf;
obj_pointer < (ulong *)((uchar *)file_buf + stb.st_size); )
digest_objfile (&obj_pointer, (ulong *)((uchar *)file_buf + stb.st_size));
if (! silent_mode)
putchar ('\n');
fclose (fp);
}
return ret_val;
}