Import GccFindHit and hunk2aout tools.
This commit is contained in:
parent
de64a69ad4
commit
7851d27114
|
@ -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() */
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue