/* * 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 #include #include #include #include #include #include #include #include #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; }