276 lines
6.4 KiB
C
276 lines
6.4 KiB
C
#include <system.h>
|
|
#include <em.h>
|
|
#include <out.h>
|
|
#include "mach.h"
|
|
#include "back.h"
|
|
|
|
/* Unportable code. Written for SUN, meant to be run on a SUN.
|
|
*/
|
|
#ifndef sun
|
|
Read above comment ...
|
|
#endif
|
|
|
|
extern File *B_out_file;
|
|
|
|
#include <a.out.h>
|
|
#include <alloc.h>
|
|
|
|
static struct exec u_header;
|
|
|
|
static long ntext, ndata, nrelo, nchar;
|
|
|
|
long B_base_address[SEGBSS+1];
|
|
|
|
static int trsize=0, drsize=0;
|
|
|
|
static struct relocation_info *u_reloc;
|
|
|
|
static reduce_name_table(), putbuf(), put_stringtablesize();
|
|
static convert_name(), convert_reloc(), init_unixheader();
|
|
|
|
output_back()
|
|
{
|
|
register int i;
|
|
register struct nlist *u_name;
|
|
register struct outrelo *rp;
|
|
|
|
/*
|
|
* Convert relocation data structures. This also requires
|
|
* some re-ordering, as SUN .o format needs has text relocation
|
|
* structures in front of the data relocation structures, whereas in
|
|
* ACK they can be in any order.
|
|
*/
|
|
|
|
nrelo = relo - reloc_info;
|
|
u_reloc = (struct relocation_info *)
|
|
Malloc((unsigned)nrelo*sizeof(struct relocation_info));
|
|
|
|
rp = reloc_info;
|
|
for (i = nrelo; i > 0; i--, rp++) {
|
|
if ( ( rp->or_sect-S_MIN) == SEGTXT &&
|
|
convert_reloc( rp, u_reloc)) {
|
|
trsize++;
|
|
u_reloc++;
|
|
}
|
|
}
|
|
rp = reloc_info;
|
|
for (i = nrelo; i > 0; i--, rp++) {
|
|
if ( ( rp->or_sect-S_MIN) != SEGTXT &&
|
|
convert_reloc( rp, u_reloc)) {
|
|
u_reloc++;
|
|
drsize++;
|
|
}
|
|
}
|
|
|
|
nrelo = trsize + drsize;
|
|
u_reloc -= nrelo;
|
|
|
|
reduce_name_table();
|
|
|
|
init_unixheader();
|
|
|
|
putbuf( (char *) &u_header, sizeof(struct exec));
|
|
putbuf( (char *) text_area, ntext);
|
|
putbuf( (char *) data_area, ndata);
|
|
putbuf((char *) u_reloc, sizeof(struct relocation_info)*nrelo);
|
|
free(u_reloc);
|
|
|
|
u_name = (struct nlist *)
|
|
Malloc((unsigned)nname * sizeof(struct nlist));
|
|
|
|
for (i = 0; i < nname ; i++) { /* The segment names can be omitted */
|
|
convert_name( &symbol_table[i], u_name++);
|
|
}
|
|
u_name -= nname;
|
|
putbuf((char *) u_name, sizeof(struct nlist)*nname);
|
|
free(u_name);
|
|
|
|
/* print( "size string_area %d\n", nchar); */
|
|
|
|
put_stringtablesize( nchar + 4);
|
|
putbuf((char *) string_area, nchar);
|
|
}
|
|
|
|
static
|
|
reduce_name_table()
|
|
{
|
|
/*
|
|
* Reduce the name table size. This is done by first marking
|
|
* the name-table entries that are needed for relocation, then
|
|
* removing the entries that are compiler-generated and not
|
|
* needed for relocation, while remembering how many entries were
|
|
* removed at each point, and then updating the relocation info.
|
|
* After that, the string table is reduced.
|
|
*/
|
|
|
|
#define S_NEEDED 0x8000
|
|
#define removable(nm) (!(nm->on_type & S_NEEDED) && *(nm->on_foff+string_area) == GENLAB)
|
|
|
|
register int *diff_index =
|
|
(int *) Malloc((unsigned)(nname + 1) * sizeof(int));
|
|
register int i;
|
|
register struct outname *np;
|
|
char *new_str;
|
|
register char *p, *q;
|
|
register struct relocation_info *rp;
|
|
|
|
*diff_index++ = 0;
|
|
rp = u_reloc;
|
|
for (i = nrelo; i > 0; i--, rp++) {
|
|
if (rp->r_extern) {
|
|
symbol_table[rp->r_symbolnum].on_type |= S_NEEDED;
|
|
}
|
|
}
|
|
|
|
np = symbol_table;
|
|
for (i = 0; i < nname; i++, np++) {
|
|
int old_diff_index = diff_index[i-1];
|
|
|
|
if (removable(np)) {
|
|
diff_index[i] = old_diff_index + 1;
|
|
}
|
|
else {
|
|
diff_index[i] = old_diff_index;
|
|
if (old_diff_index) {
|
|
symbol_table[i - old_diff_index] = *np;
|
|
}
|
|
}
|
|
}
|
|
nname -= diff_index[nname - 1];
|
|
|
|
rp = u_reloc;
|
|
for (i = nrelo; i > 0; i--, rp++) {
|
|
if (rp->r_extern) {
|
|
rp->r_symbolnum -= diff_index[rp->r_symbolnum];
|
|
}
|
|
}
|
|
|
|
free((char *)(diff_index-1));
|
|
|
|
new_str = q = Malloc((unsigned)(string - string_area));
|
|
np = symbol_table;
|
|
for (i = nname; i > 0; i--, np++) {
|
|
p = np->on_foff + string_area;
|
|
np->on_foff = q - new_str;
|
|
while (*q++ = *p) p++;
|
|
}
|
|
free(string_area);
|
|
string_area = new_str;
|
|
string = q;
|
|
}
|
|
|
|
static
|
|
init_unixheader()
|
|
{
|
|
ntext = text - text_area;
|
|
ndata = data - data_area;
|
|
nchar = string - string_area;
|
|
|
|
u_header.a_magic = OMAGIC;
|
|
u_header.a_machtype = M_68020;
|
|
u_header.a_text = ntext;
|
|
u_header.a_data = ndata;
|
|
u_header.a_bss = nbss;
|
|
u_header.a_syms = nname * sizeof(struct nlist);
|
|
u_header.a_entry = 0;
|
|
u_header.a_trsize = trsize * sizeof(struct relocation_info);
|
|
u_header.a_drsize = drsize * sizeof(struct relocation_info);
|
|
/* print( "header %o %d %d %d %d %d %d %d\n",
|
|
u_header.a_magic, u_header.a_text, u_header.a_data,
|
|
u_header.a_bss, u_header.a_syms, u_header.a_entry,
|
|
u_header.a_trsize, u_header.a_drsize);
|
|
*/
|
|
}
|
|
|
|
static
|
|
convert_reloc( a_relo, u_relo)
|
|
register struct outrelo *a_relo;
|
|
register struct relocation_info *u_relo;
|
|
{
|
|
int retval = 1;
|
|
|
|
u_relo->r_address = a_relo->or_addr;
|
|
u_relo->r_symbolnum = a_relo->or_nami;
|
|
u_relo->r_pcrel = (a_relo->or_type & RELPC) >> 3;
|
|
u_relo->r_length = 2;
|
|
if ( symbol_table[ a_relo->or_nami].on_valu == -1 ||
|
|
(symbol_table[ a_relo->or_nami].on_type & S_COM))
|
|
u_relo->r_extern = 1;
|
|
else
|
|
u_relo->r_extern = 0;
|
|
if ( u_relo->r_extern == 0) {
|
|
switch ( (symbol_table[ a_relo->or_nami].on_type & S_TYP) - S_MIN) {
|
|
case SEGTXT : u_relo->r_symbolnum = N_TEXT;
|
|
if (u_relo->r_pcrel &&
|
|
(a_relo->or_sect-S_MIN == SEGTXT))
|
|
retval = 0;
|
|
break;
|
|
case SEGCON : u_relo->r_symbolnum = N_DATA;
|
|
break;
|
|
case SEGBSS : u_relo->r_symbolnum = N_BSS;
|
|
break;
|
|
default : fprint( STDERR,
|
|
"convert_relo(): bad segment %d\n",
|
|
(symbol_table[ a_relo->or_nami].on_type & S_TYP) - S_MIN);
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
#define n_mptr n_un.n_name
|
|
#define n_str n_un.n_strx
|
|
|
|
static
|
|
convert_name( a_name, u_name)
|
|
register struct outname *a_name;
|
|
register struct nlist *u_name;
|
|
{
|
|
/* print( "naam is %s\n", a_name->on_foff + string_area); */
|
|
|
|
u_name->n_str = a_name->on_foff + 4;
|
|
if ((a_name->on_type & S_TYP) == S_UND ||
|
|
(a_name->on_type & S_EXT)) u_name->n_type = N_EXT;
|
|
else u_name->n_type = 0;
|
|
if (a_name->on_valu != -1 && (! (a_name->on_type & S_COM))) {
|
|
switch((a_name->on_type & S_TYP) - S_MIN) {
|
|
case SEGTXT:
|
|
u_name->n_type |= N_TEXT;
|
|
break;
|
|
case SEGCON:
|
|
u_name->n_type |= N_DATA;
|
|
break;
|
|
case SEGBSS:
|
|
u_name->n_type |= N_BSS;
|
|
break;
|
|
default:
|
|
fprint(STDERR, "convert_name(): bad section %d\n",
|
|
(a_name->on_type & S_TYP) - S_MIN);
|
|
break;
|
|
}
|
|
}
|
|
u_name->n_other = '\0';
|
|
u_name->n_desc = 0;
|
|
if (a_name->on_type & S_COM)
|
|
u_name->n_value = a_name->on_valu;
|
|
else if ( a_name->on_valu != -1)
|
|
u_name->n_value = a_name->on_valu +
|
|
B_base_address[( a_name->on_type & S_TYP) - S_MIN];
|
|
else
|
|
u_name->n_value = 0;
|
|
}
|
|
|
|
static
|
|
put_stringtablesize( n)
|
|
long n;
|
|
{
|
|
putbuf( (char *)&n, 4L);
|
|
}
|
|
|
|
static
|
|
putbuf(buf,n)
|
|
char *buf;
|
|
long n;
|
|
{
|
|
sys_write( B_out_file, buf, n);
|
|
}
|