This is sfaslNeXT.c in view mode; [Download] [Up]
/*
* sfaslNeXT.c: remade sfasl.c for NeXT computers
*
* by Noritake Yonezawa, May 3 1991
*/
#include <varargs.h>
#include <mach.h>
#include <sys/loader.h>
#include <stdio.h>
#include "include.h"
#undef S_DATA
#include "ext_sym.h"
struct node *find_sym();
int node_compare();
char *malloc();
char *the_start;
char *bsearch();
#define R_SCATTERED 0x80000000
struct scattered_relocation_info {
unsigned int r_scattered:1, r_pcrel:1, r_length:2, r_reserved:4, r_address:24;
long r_value;
};
static int
text_size, text_offset, text_reloff, text_nreloc, text_ordinal, data_size, data_offset, data_reloff, data_nreloc, data_ordinal, bss_size, bss_offset, bss_reloff, bss_nreloc, bss_ordinal, symoff, nsyms, stroff, strsize;
struct reloc relocation_info;
/* next 5 static after debug */
int debug;
#define MAXPATHLEN 200
#define PTABLE_EXTRA 20
static struct syment *symbol_table;
static char *start_address;
static char *my_string_table;
static int extra_bss;
static char command[200];
static char tmpfile1[50];
#define TEMPSPACE 50000
char tempspace[TEMPSPACE];
char *bil;
char
*
temp_malloc(n)
unsigned int n;
{
char *val;
val = (char *)(4 * ((((int)bil) + 4) / 4));
bil = val + n;
if (bil < tempspace + TEMPSPACE)
return val;
else {
bil = val;
return malloc(n);
}
}
/* begin reloc_file */
relocate()
{
struct scattered_relocation_info scattered_info;
char *where;
{
unsigned int new_value;
where = the_start + relocation_info.r_address;
if (relocation_info.r_address & R_SCATTERED) {
bcopy(&relocation_info, &scattered_info, sizeof(struct relocation_info));
where = the_start + scattered_info.r_address;
/*
if (scattered_info.r_pcrel)
new_value= - (int)start_address + scattered_info.r_value;
else
new_value= scattered_info.r_value;
*/
new_value = (int)start_address;
switch (scattered_info.r_length) {
case 0:
*(char *)where = new_value + *(char *)where;
break;
case 1:
*(short *)where = new_value + *(short *)where;
break;
case 2:
*(long *)where = new_value + *(long *)where;
break;
}
return;
}
if (relocation_info.r_extern) {
if (relocation_info.r_pcrel)
new_value = -(int)start_address
+ symbol_table[relocation_info.r_symbolnum].n_value;
else {
new_value =
symbol_table[relocation_info.r_symbolnum].n_value;
}
} else {
if (relocation_info.r_symbolnum == text_ordinal ||
relocation_info.r_symbolnum == data_ordinal ||
relocation_info.r_symbolnum == bss_ordinal) {
new_value = (int)start_address;
} else {
printf("\nrelocation_info {r_symbolnum= %d, r_address = %d, r_extern=0 Ignored:", relocation_info.r_address,
relocation_info.r_symbolnum);
fflush(stdout);
return;
}
}
switch (relocation_info.r_length) {
case 0:
*(char *)where = new_value + *(char *)where;
break;
case 1:
*(short *)where = new_value + *(short *)where;
break;
case 2:
*(long *)where = new_value + *(long *)where;
break;
}
}
}
/* end reloc_file */
/* free up space which is not allocated in tempspace */
#define TEMP_FREE(x) \
if (((char *)x)> tempspace+TEMPSPACE || ((char *)x)< tempspace) \
free(x)
int
fasload(faslfile)
object faslfile;
{
long fasl_vector_start;
int string_size = 0;
object memory, data;
FILE *fp;
char filename[MAXPATHLEN];
int i;
int init_address = 0;
object *old_vs_base = vs_base;
object *old_vs_top = vs_top;
bil = tempspace; /* reset tmp malloc */
extra_bss = 0;
coerce_to_filename(faslfile, filename);
faslfile = open_stream(faslfile, smm_input, Cnil, Kerror);
vs_push(faslfile);
fp = faslfile->sm.sm_fp;
if (!read_header_info(fp))
FEerror("Could not get the header", 0, 0);
symbol_table =
(struct syment *) temp_malloc(sizeof(struct syment) *
(unsigned int)nsyms);
fseek(fp, symoff, 0);
{
for (i = 0; i < nsyms; i++) {
fread((char *)&symbol_table[i], SYMESZ, 1, fp);
}
}
translate_mach_o_symbols(symbol_table, nsyms);
fseek(fp, stroff, 0);
{
int ii = 0;
if (!(ii = strsize)) {
FEerror("The string table of this file did not have any length", 0,
0);
}
/* at present the string table is located just after the symbols */
my_string_table = temp_malloc((unsigned int)ii);
if (ii != fread(my_string_table, 1, ii, fp))
FEerror("Could not read whole string table", 0, 0);
}
SEEK_TO_END_OFILE(fp);
fasl_vector_start = ftell(fp);
if (!((c_table.ptable) && *(c_table.ptable)))
build_symbol_table();
/* figure out if there is more bss space needed */
extra_bss = get_extra_bss(symbol_table, nsyms, data_size + text_size + bss_size,
&init_address, bss_size);
/* allocate some memory */
memory = alloc_object(t_cfdata);
memory->cfd.cfd_self = 0;
memory->cfd.cfd_start = 0;
memory->cfd.cfd_size = data_size + text_size + bss_size + extra_bss;
vs_push(memory);
the_start = start_address =
memory->cfd.cfd_start =
alloc_contblock(memory->cfd.cfd_size);
/*
if (fseek(fp, text_offset, 0) < 0)
FEerror("file seek error", 0, 0);
fread(the_start, text_size + data_size + bss_size, 1, fp);
*/
if (fseek(fp, text_offset, 0) < 0)
FEerror("file seek error", 0, 0);
fread(the_start, text_size, 1, fp);
if (fseek(fp, data_offset, 0) < 0)
FEerror("file seek error", 0, 0);
if (data_size != 0)
fread(the_start + text_size, data_size, 1, fp);
if (fseek(fp, bss_offset, 0) < 0)
FEerror("file seek error", 0, 0);
if (bss_size != 0)
fread(the_start + text_size + data_size, bss_size, 1, fp);
/* relocate the actual loaded text */
/*
* this looks up symbols in c.ptable and also adds new externals to that
* c.table
*/
/* relocate_symbols(NSYMS(fileheader)); */
relocate_symbols(nsyms);
fseek(fp, text_reloff, 0);
{
int nrel = text_nreloc;
for (i = 0; i < nrel; i++) {
fread((char *)&relocation_info, sizeof(struct reloc),
1, fp);
relocate();
}
}
fseek(fp, data_reloff, 0);
{
int nrel = data_nreloc;
the_start += text_size;
for (i = 0; i < nrel; i++) {
fread((char *)&relocation_info, sizeof(struct reloc),
1, fp);
relocate();
}
}
fseek(fp, bss_reloff, 0);
{
int nrel = bss_nreloc;
the_start += data_size;
for (i = 0; i < nrel; i++) {
fread((char *)&relocation_info, sizeof(struct reloc),
1, fp);
relocate();
}
the_start -= data_size;
}
/* end of relocation */
/* read in the fasl vector */
fseek(fp, fasl_vector_start, 0);
if (feof(fp)) {
data = 0;
} else {
data = read_fasl_vector(faslfile);
vs_push(data);
}
close_stream(faslfile, 1);
TEMP_FREE(my_string_table);
TEMP_FREE(symbol_table);
asm("trap #2");
call_init(init_address, memory, data);
vs_base = old_vs_base;
vs_top = old_vs_top;
if (symbol_value(Vload_verbose) != Cnil)
printf("start address -T %x ", memory->cfd.cfd_start);
return (memory->cfd.cfd_size);
}
struct node *
find_sym(sym, name)
struct syment *sym;
char *name;
{
char tem[SYMNMLEN + 1];
tem[SYMNMLEN] = 0;
if (name == 0)
name = SYM_NAME(sym);
{
struct node joe, *answ;
joe.string = name;
answ = (struct node *) bsearch((char *)(&joe), (char *)(c_table.ptable),
c_table.length,
sizeof(struct node), node_compare);
return answ;
}
}
get_extra_bss(symbol_table, length, start, ptr, bsssize)
int length, bsssize;
struct syment *symbol_table;
int *ptr; /* store init address offset here */
{
int result = start;
int next_bss = start - bsssize;
struct syment *end, *sym;
char tem[SYMNMLEN + 1];
end = symbol_table + length;
for (sym = symbol_table; sym < end; sym++) {
tem; /* ignored */
if (SYM_EXTERNAL_P(sym) && SYM_UNDEF_P(sym))
/* external bss so not included in size of bss for file */
{
int val = sym->n_value;
if (val && c_table.ptable
&& (0 == find_sym(sym, 0))) {
sym->n_value = result;
result += val;
}
}
sym += NUM_AUX(sym);
}
return (result - start);
}
/* go through the symbol table changing the addresses of the symbols
to reflect the current cfd_start */
relocate_symbols(nsyms)
int nsyms;
{
struct syment *sym;
unsigned int typ;
int i;
char *str;
char tem[SYMNMLEN + 1];
tem[SYMNMLEN] = 0;
for (i = 0; i < nsyms; i++) {
sym = &symbol_table[i];
typ = NTYPE(sym);
#ifdef N_STAB
if (N_STAB & sym->n_type)
continue; /* skip: It is for dbx only */
#endif
typ = N_SECTION(sym);
/* if(sym->n_type & N_EXT) should add the symbol name,
so it would be accessible by future loads */
switch (typ) {
case N_ABS:
case N_TEXT:
case N_DATA:
case N_BSS:
str = SYM_NAME(sym);
sym->n_value = (int)start_address;
break;
case N_UNDEF:
str = SYM_NAME(sym);
set_symbol_address(sym, str);
break;
default:
break;
}
sym += NUM_AUX(sym);
}
}
/*
STEPS:
1) read in the symbol table from the file,
2) go through the symbol table, relocating external entries.
3) for i <=2 go thru the relocation information for this section
relocating the text.
4) done.
*/
set_symbol_address(sym, string)
struct syment *sym;
char *string;
{
struct node *answ;
if (c_table.ptable) {
answ = find_sym(sym, string);
if (answ) {
/*
* the old value of sym->n_value is the length of the common area
* starting at this address
*/
sym->n_value = answ->address;
} else {
{
char *name;
name = malloc(1 + strlen(string));
strcpy(name, string);
sym->n_value = sym->n_value + (unsigned int)the_start;
add_symbol(string, sym->n_value, NULL);
}
fprintf(stdout, "undefined %s symbol", string);
fflush(stdout);
}
} else {
FEerror("symbol table not loaded", 0, 0);
}
}
/*
#define ADD_SYMBOL(name) add_symbol("name",(int) &(name),0)
Use the add_symbol to add a c symbol, which you want to refer
to in subsequent loads. The address used in subsequent loads,
will be the load address of the current symbol.
Such a symbol may only be added once, since subsequent references
will try to link to the old address.
*/
build_symbol_table()
{
printf("Building symbol table for %s ..\n", kcl_self);
fflush(stdout);
sprintf(tmpfile1, "/tmp/rsym%d", getpid());
coerce_to_filename(symbol_value(siVsystem_directory),
system_directory);
sprintf(command, "%srsym %s %s", system_directory, kcl_self, tmpfile1);
if (system(command) != 0)
FEerror("The rsym command ~a failed .", 1, make_simple_string(command)
);
read_special_symbols(tmpfile1);
unlink(tmpfile1);
qsort((char *)(c_table.ptable), (int)(c_table.length), sizeof(struct node), node_compare);
}
/*to do:Addition of one symbol to the ptable is very slow, because we
sort each time! */
add_symbol(va_alist)
va_dcl
{
char *string;
int address;
int nstr, i;
va_list ap;
/* terminate arg list with NULL pointer */
if (!(c_table.ptable))
return; /* this is in a function before ptable is
* init */
nstr = 0;
/* count the number of strings */
va_start(ap);
while (va_arg(ap, char *)!=0) {
nstr++;
va_arg(ap, int);
if (nstr > 1000)
FEerror("Did you really give 1000 strings or just forget 0 ending", 0, 0);
};
va_end(ap);
va_start(ap);
if ((int)((c_table.alloc_length) - (c_table.length)) - nstr > 0) {
BEGIN:
for (i = 0; i < 2 * nstr; i = i + 2) {
string = va_arg(ap, char *);
if (find_sym(0, string)) {
FEerror("The string ~a is already in the ptable", 1,
make_simple_string(string));
};
{
struct node *u;
u = ((*(c_table.ptable)) + ((c_table.length) + (i / 2)));
u->string = string;
u->address = va_arg(ap, int);
}
}
(c_table.length) = (c_table.length) + nstr;
qsort((char *)(c_table.ptable), (int)(c_table.length), sizeof(struct node), node_compare);
} else
/* grow the ptable */
{
TABL *new, *old_pt;
new =
(TABL *) malloc(sizeof(struct node)
* ((c_table.alloc_length) = ((c_table.length) + nstr + PTABLE_EXTRA)));
old_pt = (c_table.ptable);
/* copy it */
{
register int i;
for (i = 0; i < c_table.length; i++) {
(*new)[i].string = (*old_pt)[i].string;
(*new)[i].address = (*old_pt)[i].address;
}
}
(c_table.ptable) = new;
free((char *)old_pt);
goto BEGIN;
}
va_end(ap);
}
int
read_header_info(fp)
FILE *fp;
{
struct mach_header mach_header;
char *hdrbuf;
struct load_command *load_command;
struct segment_command *segment_command;
struct section *section;
struct symtab_command *symtab_command;
struct symseg_command *symseg_command;
int ordinal;
int len, cmd, seg;
ordinal = 1;
fseek(fp, 0L, 0);
len = fread((char *)&mach_header, sizeof(struct mach_header), 1, fp);
if (len == 1 && mach_header.magic == MH_MAGIC) {
hdrbuf = malloc(mach_header.sizeofcmds);
len = fread(hdrbuf, mach_header.sizeofcmds, 1, fp);
if (len != 1) {
fprintf(stderr, "failure reading Mach-O load commands\n");
return 0;
}
load_command = (struct load_command *) hdrbuf;
for (cmd = 0; cmd < mach_header.ncmds; ++cmd) {
switch (load_command->cmd) {
case LC_SEGMENT:
segment_command = (struct segment_command *) load_command;
section = (struct section *) ((char *)(segment_command + 1));
for (seg = 0; seg < segment_command->nsects; ++seg, ++section, ++ordinal) {
if (!strncmp(SECT_TEXT, section->sectname, sizeof section->sectname)) {
text_size = section->size;
text_offset = section->offset;
text_reloff = section->reloff;
text_nreloc = section->nreloc;
text_ordinal = ordinal;
} else if (!strncmp(SECT_DATA, section->sectname, sizeof section->sectname)) {
data_size = section->size;
data_offset = section->offset;
data_reloff = section->reloff;
data_nreloc = section->nreloc;
data_ordinal = ordinal;
} else if (!strncmp(SECT_BSS, section->sectname, sizeof section->sectname)) {
bss_size = section->size;
bss_offset = section->offset;
bss_reloff = section->reloff;
bss_nreloc = section->nreloc;
bss_ordinal = ordinal;
}
}
break;
case LC_SYMTAB:
symtab_command = (struct symtab_command *) load_command;
symoff = symtab_command->symoff;
nsyms = symtab_command->nsyms;
stroff = symtab_command->stroff;
strsize = symtab_command->strsize;
break;
}
load_command = (struct load_command *)
((char *)load_command + load_command->cmdsize);
}
free(hdrbuf);
return 1;
}
return 0;
}
#ifndef N_SLINE
#define N_SLINE 0x44
#endif
#ifndef N_DSLINE
#define N_DSLINE 0x46
#endif
#ifndef N_BSLINE
#define N_BSLINE 0x48
#endif
translate_mach_o_symbols(symbol_table, nsyms)
struct syment *symbol_table;
int nsyms;
{
int i;
struct syment *sym;
for (i = 0; i < nsyms; ++i) {
if (((sym = &symbol_table[i])->n_type & ~N_EXT) == N_SECT) {
if (sym->n_sect == text_ordinal)
sym->n_type = (sym->n_type & N_EXT) | N_TEXT;
else if (sym->n_sect == data_ordinal)
sym->n_type = (sym->n_type & N_EXT) | N_DATA;
else if (sym->n_sect == bss_ordinal)
sym->n_type = (sym->n_type & N_EXT) | N_BSS;
else
fprintf(stderr, "unknown section referenced in symbols\n");
sym->n_sect = 0;
} else if (sym->n_type == N_SLINE) {
if (sym->n_sect == text_ordinal)
sym->n_type = N_SLINE;
else if (sym->n_sect == data_ordinal)
sym->n_type = N_DSLINE;
else if (sym->n_sect == bss_ordinal)
sym->n_type = N_BSLINE;
else
fprintf(stderr, "unknown section referenced in debugging symbols");
}
}
}
#define RELOC_EXTERN_P(r) ((r)->r_extern)
#define RELOC_TYPE(r) ((r)->r_symbolnum)
translate_mach_o_relocation(reloc)
struct relocation_info *reloc;
{
int i;
if (!RELOC_EXTERN_P(reloc)) {
if (RELOC_TYPE(reloc) == R_ABS)
RELOC_TYPE(reloc) = N_ABS;
else if (RELOC_TYPE(reloc) == text_ordinal)
RELOC_TYPE(reloc) = N_TEXT;
else if (RELOC_TYPE(reloc) == data_ordinal)
RELOC_TYPE(reloc) = N_DATA;
else if (RELOC_TYPE(reloc) == bss_ordinal)
RELOC_TYPE(reloc) = N_BSS;
else
fprintf(stderr, "unknown section ordinal in relocation info\n");
}
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.