This is sfasl.c in view mode; [Download] [Up]
/* Copyright William Schelter. All rights reserved. There is a companion file rsym.c which is used to build a list of the external symbols in a COFF or A.OUT object file, for example saved_kcl. These are loaded into kcl, and the linking is done directly inside kcl. This saves a good deal of time. For example a tiny file foo.o with one definition can be loaded in .04 seconds. This is much faster than previously possible in kcl. The function fasload from unixfasl.c is replaced by the fasload in this file. this file is included in unixfasl.c via #include "../c/sfasl.c" */ /* for testing in standalone manner define STAND You may then compile this file cc -g -DSTAND -DDEBUG -I../hn a.out /tmp/foo.o /public/akcl/unixport/saved_kcl /public/akcl/unixport/ will write a /tmp/sfasltest file which you can use comp to compare with one produced by ld. */ #ifdef STAND #include "config.h" #include <stdio.h> #include "mdefs.h" #else #include "include.h" #undef S_DATA #endif #include <varargs.h> #include "ext_sym.h" struct node * find_sym(); int node_compare(); char *malloc(); char *the_start; char *bsearch(); struct reloc relocation_info; /* next 5 static after debug */ int debug; #ifdef DEBUG #define debug sfasldebug int sfasldebug=0; #define dprintf(s,ar) if(debug) { printf(" ( s )",ar) ; fflush(stdout);} #define STAT #else /* end debug */ #define dprintf(s,ar) #define STAT static #endif #define MAXPATHLEN 200 #define PTABLE_EXTRA 20 STAT struct syment *symbol_table; STAT char *start_address; STAT char *my_string_table; STAT int extra_bss; STAT char command[200]; STAT char tmpfile1 [50]; #ifndef describe_sym #define describe_sym(a) #endif #ifdef STAND #include "rel_stand.c" #endif #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; dprintf( having to use regular malloc for %d,n); return malloc(n);} } /* begin reloc_file */ #include RELOC_FILE /* 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; struct filehdr fileheader; #ifdef COFF struct scnhdr sectionheader; struct scnhdr section[10]; struct aouthdr header; #endif int textsize, datasize, bsssize,nsyms; int string_size=0; object memory, data; FILE *fp; char filename[MAXPATHLEN]; int i; int init_address=0; #ifndef STAND object *old_vs_base = vs_base; object *old_vs_top = vs_top; #endif bil=tempspace; /* reset tmp malloc */ extra_bss=0; #ifdef STAND strcpy(filename,faslfile); fp=fopen(filename,RDONLY); #else coerce_to_filename(faslfile, filename); faslfile = open_stream(faslfile, smm_input, Cnil, Kerror); vs_push(faslfile); fp = faslfile->sm.sm_fp; #endif HEADER_SEEK(fp); if(!fread((char *)&fileheader, sizeof(struct filehdr), 1, fp)) FEerror("Could not get the header",0,0); nsyms = NSYMS(fileheader); #ifdef COFF #ifdef AIX3 setup_for_aix_load(); #endif fread(&header,1,fileheader.f_opthdr,fp); fread(§ion[1],fileheader.f_nscns,sizeof (struct scnhdr),fp); textsize = section[TEXT_NSCN].s_size; datasize = section[DATA_NSCN].s_size; if (strcmp(section[BSS_NSCN].s_name, ".bss") == 0) bsssize=section[BSS_NSCN].s_size; else bsssize=section[BSS_NSCN].s_size = 0; #endif #ifdef BSD textsize=fileheader.a_text; datasize=fileheader.a_data; bsssize=fileheader.a_bss; #endif symbol_table = (struct syment *) temp_malloc(sizeof(struct syment)* (unsigned int)nsyms); fseek(fp,(int)( N_SYMOFF(fileheader)), 0); { for (i = 0; i < nsyms; i++) {fread((char *)&symbol_table[i], SYMESZ, 1, fp); dprintf( symbol table %d , i); if (debug) describe_sym(i); dprintf( at %d , &symbol_table[i]); #ifdef HPUX symbol_table[i].n_un.n_strx = string_size; dprintf(string_size %d, string_size); string_size += symbol_table[i].n_length + 1; fseek(fp,(int)symbol_table[i].n_length,1); #endif } } /* on MP386 The sizeof(struct syment) = 20, while only SYMESZ =18. So we had to read one at a time. fread((char *)symbol_table, SYMESZ*fileheader.f_nsyms,1,fp); */ #ifdef READ_IN_STRING_TABLE my_string_table=READ_IN_STRING_TABLE(fp,string_size); #else #ifdef MUST_SEEK_TO_STROFF fseek(fp,N_STROFF(fileheader),0); #endif {int ii=0; if (!fread((char *)&ii,sizeof(int),1,fp)) {FEerror("The string table of this file did not have any length",0, 0);} fseek(fp,-4,1); /* at present the string table is located just after the symbols */ my_string_table=temp_malloc((unsigned int)ii); dprintf( string table leng = %d, ii); if(ii!=fread(my_string_table,1,ii,fp)) FEerror("Could not read whole string table",0,0) ; } #endif #ifdef SEEK_TO_END_OFILE SEEK_TO_END_OFILE(fp); #else while ((i = getc(fp)) == 0) ; ungetc(i, fp); #endif 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,datasize+textsize+bsssize, &init_address,bsssize); /* allocate some memory */ #ifndef STAND memory = alloc_object(t_cfdata); memory->cfd.cfd_self = 0; memory->cfd.cfd_start = 0; memory->cfd.cfd_size = datasize+textsize+bsssize + extra_bss; vs_push(memory); the_start=start_address= memory->cfd.cfd_start = alloc_contblock(memory->cfd.cfd_size); #else the_start=start_address = malloc(datasize+textsize+bsssize + extra_bss + 0x80000); the_start=start_address= (char *)( 0x1000* ((((int)the_start + 0x70000) + 0x1000)/0x1000)); #endif dprintf( code size %d , datasize+textsize+bsssize + extra_bss); if (fseek(fp,N_TXTOFF(fileheader) ,0) < 0) FEerror("file seek error",0,0); fread(the_start, textsize + datasize, 1, fp); dprintf(read into memory text +data %d bytes, textsize + datasize); /* relocate the actual loaded text */ dprintf( the_start %x, the_start); /* record which symbols are used */ #ifdef SYM_USED {int j=0; for(j=1; j< BSS_NSCN ; j++) { dprintf( relocating section %d \n,j); if (section[j].s_nreloc) fseek(fp,section[j].s_relptr,0); for(i=0; i < section[j].s_nreloc; i++) { struct syment *sym; fread(&relocation_info, RELSZ, 1, fp); sym = & symbol_table[relocation_info.r_symndx]; if (TC_SYMBOL_P(sym)) SYM_USED(sym) = 1; }}} #endif /* this looks up symbols in c.ptable and also adds new externals to that c.table */ relocate_symbols(NSYMS(fileheader)); #ifdef COFF {int j=0; for(j=1; j< BSS_NSCN ; j++) { dprintf( relocating section %d \n,j); if (section[j].s_nreloc) fseek(fp,section[j].s_relptr,0); for(i=0; i < section[j].s_nreloc; i++) /* RELSZ = sizeof(relocation_info) */ {fread(&relocation_info, RELSZ, 1, fp); dprintf(relocating %d,i); relocate();}; }}; #endif #ifdef BSD fseek(fp,N_RELOFF(fileheader),0); {int nrel = (fileheader.a_trsize/sizeof(struct reloc)); for (i=0; i < nrel; i++) {fread((char *)&relocation_info, sizeof(struct reloc), 1, fp); dprintf(relocating %d,i); relocate(); } } #ifdef N_DRELOFF fseek (fp, N_DRELOFF(fileheader), 0); #endif {int nrel = (fileheader.a_drsize/sizeof(struct reloc)); the_start += fileheader.a_text; for (i=0; i < nrel; i++) {fread((char *)&relocation_info, sizeof(struct reloc), 1, fp); dprintf(relocating %d,i); relocate(); } } #endif /* end of relocation */ dprintf( END OF RELOCATION \n,0); dprintf( invoking init function at %x, start_address) dprintf( textsize is %x,textsize); dprintf( datasize is %x,datasize); /* 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); #ifdef COFF dprintf( read fasl now symbols %d , fileheader.f_nsyms); #endif } close_stream(faslfile, 1); /* { int fd; fd = creat ("xsakcl.bits", 0777); write (fd, memory->cfd.cfd_start, textsize + datasize); close (fd); fd = open ("xsl2.bits", 0); read (fd, memory->cfd.cfd_start, memory->cfd.cfd_size); close (fd); } */ #ifndef STAND TEMP_FREE(my_string_table); TEMP_FREE(symbol_table); #ifdef CLEAR_CACHE CLEAR_CACHE; #endif 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); #endif {FILE *out; out=fopen("/tmp/sfasltest","w"); fwrite((char *)&fileheader, sizeof(struct filehdr), 1, out); fwrite(start_address,sizeof(char),datasize+textsize,out); fclose(out);} printf("\n(start %x)\n",start_address); } #ifdef AIX3 struct syment * get_symbol(name,scnum,symbol_table,length) char *name; int scnum,length; struct syment *symbol_table; { struct syment *end,*sym; char tem[SYMNMLEN +1]; char *na; end =symbol_table + length; for(sym=symbol_table; sym < end; sym += (NUM_AUX(sym) +1)) {if ((sym)->n_scnum == scnum) { na=SYM_NAME(sym); if (strcmp(name,na) == 0) {return sym;}}} return 0;} #endif /* aix3 */ 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++) { #ifdef FIND_INIT FIND_INIT #endif #ifdef AIX3 /* we later go through the relocation entries making this 1 for symbols used */ #ifdef SYM_USED if(TC_SYMBOL_P(sym)) {SYM_USED(sym) = 0;} #endif /* fix up the external refer to _ptrgl to be local ref */ if (sym->n_scnum == 0 && strcmp(sym->n_name,"_ptrgl")==0) {struct syment* s = get_symbol("._ptrgl",TEXT_NSCN,symbol_table,length); if (s ==0) FEerror("bad glue",0); sym->n_value = next_bss ; ptrgl_offset = next_bss; ptrgl_text = s->n_value; next_bss += 0xc; sym->n_scnum = DATA_NSCN; ((union auxent *)(sym+1))->x_csect.x_scnlen = 0xc; } if(sym->n_scnum != BSS_NSCN) goto NEXT; if(SYM_EXTERNAL_P(sym)) {int val=sym->n_value; struct node joe; if (val && c_table.ptable) {struct node *answ; answ= find_sym(sym,0); if(answ) {sym->n_value = answ->address ; sym->n_scnum = N_UNDEF; val= ((union auxent *)(sym+1))->x_csect.x_scnlen; result -= val; goto NEXT; }} } /* reallocate the bss space */ if (sym->n_value == 0) {result += ((union auxent *)(sym+1))->x_csect.x_scnlen;} sym->n_value = next_bss; next_bss += ((union auxent *)(sym+1))->x_csect.x_scnlen; NEXT: ; /* end aix3 */ #endif #ifdef BSD tem; /* ignored */ if(SYM_EXTERNAL_P(sym) && SYM_UNDEF_P(sym)) #endif #ifdef COFF if(0) /* what we really want is if (sym->n_scnum==0 && sym->n_sclass == C_EXT && !(bsearch(..in ptable for this symbol))) Since this won't allow loading in of a new external array char foo[10] not ok static foo[10] ok. for the moment we give undefined symbol warning.. Should really go through the symbols, recording the external addr for ones found in ptable, and for the ones not in ptable set some flag, and add up the extra_bss required. Then when you have the new memory chunk in hand, you could make the pass setting the relative addresses. for the ones you flagged last time. */ #endif /* 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(length) unsigned int length; {struct syment *end,*sym; unsigned int typ; char *str; char tem[SYMNMLEN +1]; tem[SYMNMLEN]=0; end =symbol_table + length; for(sym=symbol_table; sym < end; sym++) { typ=NTYPE(sym); #ifdef BSD #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 */ #endif switch (typ) { #ifdef BSD case N_ABS : case N_TEXT: case N_DATA: case N_BSS: #endif #ifdef COFF case TEXT_NSCN : case DATA_NSCN: case BSS_NSCN : #endif str=SYM_NAME(sym); dprintf( for sym %s ,str) dprintf( new value will be start %x, start_address); #ifdef AIX3 if(N_SECTION(sym) == DATA_NSCN && NUM_AUX(sym) && allocate_toc(sym)) break; #endif sym->n_value = (int)start_address; break; case N_UNDEF: str=SYM_NAME(sym); dprintf( undef symbol %s ,str); dprintf( symbol diff %d , sym - symbol_table); describe_sym(sym-symbol_table); set_symbol_address(sym,str); describe_sym(sym-symbol_table); break; default: #ifdef COFF dprintf(am ignoring a scnum %d,(sym->n_scnum)); #endif 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) { dprintf(string %s, string); answ = find_sym(sym,string); dprintf(answ %d , (answ ? answ->address : -1)); if(answ) { #ifdef COFF #ifdef _AIX370 if (NTYPE(sym) == N_UNDEF) sym->n_value = answ->address; else #endif sym->n_value = answ->address -sym->n_value; /* for symbols in the local data,text and bss this gets added on when we add the current value */ #endif #ifdef BSD /* the old value of sym->n_value is the length of the common area starting at this address */ sym->n_value = answ->address; #endif #ifdef AIX3 fix_undef_toc_address(answ,sym,string); #endif } else { #ifdef BSD {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); } #endif 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); dprintf(c_table %d , c_table.length); 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); } /* this is in fat_string.c for the moment */ /* read_special_symbols(symfile) char *symfile; {FILE *symin; char *symbols; int i,jj; struct lsymbol_table tab; if (!(symin=fopen(symfile,"r"))) {perror(symfile);exit(1);}; fread((char *)&tab,sizeof(tab),1,symin); symbols=malloc(tab.tot_leng); c_table.alloc_length=( (PTABLE_EXTRA+ tab.n_symbols)); c_table.ptable =(TABL *)malloc(sizeof(struct node) * (c_table.alloc_length)); if (!(c_table.ptable)) {perror("could not allocate"); exit(1);}; i=0; c_table.length = tab.n_symbols; while(i < tab.n_symbols) { fread((char *)&jj,sizeof(int),1,symin); (SYM_ADDRESS(c_table,i))=jj; SYM_STRING(c_table,i)=symbols; while( *(symbols++) = getc(symin)) {;} dprintf( name %s , SYM_STRING(c_table,i)); dprintf( address %d , jj); i++; } } */ #ifdef DEBUG print_name(p) struct syment *p; {char tem[10],*name; name=SYM_NAME(p); name= (((p)->_n._n_n._n_zeroes == 0) ? &my_string_table[(p)->_n._n_n._n_offset] : ((p)->_n._n_name[SYMNMLEN -1] ? (strncpy(tem,(p)->_n._n_name, SYMNMLEN), (char *)tem) : (p)->_n._n_name )); printf("(name:|%s|)",name); printf("(sclass 0x%x)",p->n_sclass); printf("(external_p 0x%x)",SYM_EXTERNAL_P(p)); printf("(n_type 0x%x)",p->n_type); printf("(n_value 0x%x)",p->n_value); printf("(numaux 0x%x)\n",NUM_AUX(p)); fflush(stdout); } #endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.