amigaos-cross-toolchain6/tools/hunk2aout.c

987 lines
31 KiB
C

/*
* 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include "defs.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
char *version_tag = "\0$VER: hunk2aout 2.0 (1.3.97)\r\n";
static uint32_t *file_buf = 0;
/* if set no progress reports are output */
static 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 */
uint8_t type;
uint8_t pad1; /* really n_other */
short hunk_num; /* really n_desc */
uint32_t value;
};
struct table {
void *base;
int el_size;
int i;
int max_el;
};
static 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 next_hunk(uint32_t **hp)
{
/* skip over the length field and the there given length */
*hp += 1 + GETLONG(**hp);
}
/* save a lot of space for duplicate string, that all say "only.. with size.. */
static void 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.
*/
static char *str_table = 0;
static int strtab_size, strtab_index;
static int 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 strfree (int str)
{
strtab_index = str;
}
/****************************************************************************/
static void 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, (uint8_t *)tab->base + (tab->i++ * tab->el_size), tab->el_size);
}
static void 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 add_symbol (struct table *tab, int num, uint32_t 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);
}
/****************************************************************************/
static void digest_objfile (uint32_t **file_pptr, uint32_t *max_fp)
{
/* this makes it less clumsy.. */
uint32_t *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 ;-))
*/
uint8_t *text, *data, *chip_data;
uint32_t 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 = 0;
data_hunks.i = 0;
bss_hunks.i = 0;
chip_data_hunks.i = 0;
reloc_tab.i = 0;
symbol_tab.i = 0;
while (units < 2)
{
switch (HUNK_VALUE(GETLONG(*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 (GETLONG(file_ptr[0])) next_hunk (& file_ptr);
/* skip null-word, table_size, F & L, and size-table */
file_ptr += 4 + (GETLONG(file_ptr[1]) - GETLONG(file_ptr[2]) + 1);
break;
case HUNK_CODE:
DP(("HUNK_CODE, size = $%x\n", GETLONG(file_ptr[0]) << 2));
is_chip = HUNK_ATTRIBUTE(GETLONG(file_ptr[-1])) == HUNK_ATTR_CHIP;
if (is_chip)
fprintf (stderr, "CHIP code hunks are not supported, "
"ignoring CHIP attribute\n");
if (GETLONG(file_ptr[0]))
{
/* only accept one code hunk with size != 0 */
if (hdr.a_text)
limit_hunk ("code");
else
{
text = (uint8_t *)&file_ptr[1];
hdr.a_text = GETLONG(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", GETLONG(file_ptr[0]) << 2));
is_chip = HUNK_ATTRIBUTE(GETLONG(file_ptr[-1])) == HUNK_ATTR_CHIP;
if (GETLONG(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 = (uint8_t *) &file_ptr[1];
chip_data_size = GETLONG(file_ptr[0]) << 2;
}
}
else
{
if (hdr.a_data)
limit_hunk ("data");
else
{
data = (uint8_t *)&file_ptr[1];
hdr.a_data = GETLONG(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", GETLONG(file_ptr[0]) << 2));
is_chip = HUNK_ATTRIBUTE(file_ptr[-1]) == HUNK_ATTR_CHIP;
if (GETLONG(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 = GETLONG(file_ptr[0]) << 2;
}
else
{
if (hdr.a_bss)
limit_hunk ("bss");
else
hdr.a_bss = GETLONG(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 = GETLONG(file_ptr[-1]) >= HUNK_DREL32;
size = (brel ? HUNK_DREL8 : HUNK_RELOC8) - GETLONG(file_ptr[-1]);
DP(("HUNK_RELOC/DREL ($%x), brel = %d, size = %d\n", GETLONG(file_ptr[-1]), brel, size));
while (GETLONG(file_ptr[0]))
{
long to_reloc = GETLONG(file_ptr[1]);
long n = GETLONG(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, GETLONG(file_ptr[n+2]),
size, size != 2, brel, -1);
file_ptr += GETLONG(file_ptr[0]) + 2;
}
}
file_ptr++;
break;
case HUNK_SYMBOL:
case HUNK_EXT:
DP(("HUNK_SYMBOL/EXT\n"));
while (GETLONG(file_ptr[0]))
{
int n, size, brel;
#if 0
DP((" EXT_: %d, %-*.*s\n", file_ptr[0] >> 24,
4*(file_ptr[0] & 0xffffff), 4*(file_ptr[0] & 0xffffff), &file_ptr[1]));
#endif
switch (GETLONG(file_ptr[0]) >> 24)
{
case EXT_SYMB:
case EXT_DEF:
case EXT_ABS:
case EXT_RES:
add_symbol (&symbol_tab, hunk_num-1,
GETLONG(file_ptr[0]),
file_ptr[1+(GETLONG(file_ptr[0]) & 0xffffff)],
(char *)&file_ptr[1]);
file_ptr += 2+(GETLONG(file_ptr[0]) & 0xffffff);
break;
case EXT_COMMON:
/* first define the common symbol, then add the relocs */
add_symbol (&symbol_tab, hunk_num-1,
GETLONG(file_ptr[0]),
file_ptr[1+(GETLONG(file_ptr[0]) & 0xffffff)],
(char *)&file_ptr[1]);
file_ptr += 2+(GETLONG(file_ptr[0]) & 0xffffff);
/* now the references, translated into relocs */
for (n = file_ptr[0]; n--; )
add_reloc (&reloc_tab, hunk_num - 1, -1, GETLONG(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 = GETLONG(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, GETLONG(file_ptr[0]),
0, (char *)&file_ptr[1]);
file_ptr += 1+(GETLONG(file_ptr[0]) & 0xffffff);
/* now the references, translated into relocs */
for (n = GETLONG(file_ptr[0]); n; n--)
add_reloc (&reloc_tab, hunk_num - 1, -1, GETLONG(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",
GETLONG(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",
GETLONG(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);
}
static 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 = NULL;
/* this is the mentioned hunk-gap */
uint32_t offset = 0;
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;
uint8_t *core_addr;
uint32_t 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)
*(uint32_t *)(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)
*(uint32_t *)(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);
*(uint32_t *)str_table = PUTLONG(strtab_index);
{
struct exec hdr_be;;
hdr_be.a_mid = PUTWORD(hdr->a_mid);
hdr_be.a_magic = PUTWORD(hdr->a_magic);
hdr_be.a_text = PUTLONG(hdr->a_text);
hdr_be.a_data = PUTLONG(hdr->a_data);
hdr_be.a_bss = PUTLONG(hdr->a_bss);
hdr_be.a_syms = PUTLONG(hdr->a_syms);
hdr_be.a_entry = PUTLONG(hdr->a_entry);
hdr_be.a_trsize = PUTLONG(hdr->a_trsize);
hdr_be.a_drsize = PUTLONG(hdr->a_drsize);
write (fd, (char *)&hdr_be, sizeof (hdr_be));
}
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;
uint32_t *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, (int)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 < (uint32_t *)((uint8_t *)file_buf + stb.st_size); )
digest_objfile (&obj_pointer, (uint32_t *)((uint8_t *)file_buf + stb.st_size));
if (! silent_mode)
putchar ('\n');
fclose (fp);
}
return ret_val;
}