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.