/* * Copyright (C) 1996-1998 Ilya Ryzhenkov (orangy@inetlab.com) */ #include "dlmstr.h" static char buf[255]; void patchFrame(TCoff *cf); static void err(char *str) { printf("COFF FATAL : %s\n",str); exit(1); } TCoff *LoadCoff(char *fname) { int sz,i,f; Long strsize; FILHDR *fh=(FILHDR*)malloc(FILHSZ); TCoff *cf=(TCoff*)malloc(sizeof(TCoff)); if (!fh) err("memory error"); f=open(fname,O_RDWR|O_BINARY); if (f==-1) err("file not found"); sz=read(f,fh,FILHSZ); if (sz!=FILHSZ) err("invalid file"); if ((fh->f_magic!=I386MAGIC) || (fh->f_opthdr) || ((fh->f_flags&0xB))) { if (fh->f_magic!=I386MAGIC) printf("This file is not COFF\n"); if (fh->f_opthdr) printf("This file has second header\n"); if (fh->f_flags & F_RELFLG) printf("Relocation info was stripped from this file\n"); if (fh->f_flags & F_EXEC) printf("File is executable - not object\n"); if (fh->f_flags & F_LSYMS) printf("Local symbols was stripped from this file\n"); err("Unsupported file type"); } lseek(f,fh->f_opthdr,SEEK_CUR); cf->NumSect=fh->f_nscns; cf->NumSym=fh->f_nsyms; cf->SymOffset=fh->f_symptr; free(fh); cf->Sections=(SCNHDR*)malloc(SCNHSZ*cf->NumSect); if (!cf->Sections) err("memory error"); // allocate array of pointers for reloc data for each section cf->Relocs=(RELOC**)malloc(sizeof(RELOC*)*cf->NumSect); if (!cf->Relocs) err("memory error"); // allocate array of pointers for sect data for each section cf->SectData=(SCNDTA*)malloc(sizeof(SCNDTA)*cf->NumSect); if (!cf->SectData) err("memory error"); sz=read(f,cf->Sections,SCNHSZ*cf->NumSect); if (sz!=SCNHSZ*cf->NumSect) err("invalid file"); // Now loading relocation tables for (i=0; iNumSect; i++) { if (cf->Sections[i].s_nreloc) // load reloc for section { cf->Relocs[i]=(RELOC*)malloc(cf->Sections[i].s_nreloc*RELSZ); if (!cf->Relocs[i]) err("memory error"); sz=lseek(f,cf->Sections[i].s_relptr,SEEK_SET); if (sz!=cf->Sections[i].s_relptr) err("invalid file"); sz=read(f,cf->Relocs[i],cf->Sections[i].s_nreloc*RELSZ); if (sz!=cf->Sections[i].s_nreloc*RELSZ) err("invalid file"); } else cf->Relocs[i]=NULL; if (cf->Sections[i].s_size && cf->Sections[i].s_scnptr) /* load data for section*/ { cf->SectData[i]=(SCNDTA)malloc(cf->Sections[i].s_size); if (!cf->SectData[i]) err("memory error"); sz=lseek(f,cf->Sections[i].s_scnptr,SEEK_SET); if (sz!=cf->Sections[i].s_scnptr) err("invalid file"); sz=read(f,cf->SectData[i],cf->Sections[i].s_size); if (sz!=cf->Sections[i].s_size) err("invalid file"); } else cf->SectData[i]=NULL; } strsize=4; cf->Symbols=(SYMENT*)malloc(SYMESZ*cf->NumSym); if (!cf->Symbols) err("memory error"); sz=lseek(f,cf->SymOffset,SEEK_SET); if (sz!=cf->SymOffset) err("invalid file"); sz=read(f,cf->Symbols,SYMESZ*cf->NumSym); if (sz!=SYMESZ*cf->NumSym) err("invalid file"); sz=read(f,&strsize,sizeof(Long)); if (sz!=sizeof(Long)) err("invalid file"); cf->Strings=(char*)malloc(strsize); if (!cf->Strings) err("memory error"); cf->Strings[0]=0; if (strsize>4) { sz=read(f,cf->Strings+4,strsize-4); if (sz!=strsize-4) err("invalid file"); } close(f); patchFrame(cf); return cf; } void DestroyCoff(TCoff *cf) { int i; for (i=0; iNumSect; i++) if (cf->Relocs[i]) free(cf->Relocs[i]); free(cf->Relocs); free(cf->Symbols); free(cf->Sections); free(cf->Strings); free(cf->SectData); free(cf); } Long DlmAddStr(TDlm *dl,char *name,int is8) { /* Returns offset in strings table */ Long len,retval,i; if (!is8) len=strlen(name)+1; else { len=0; while (len<9 && name[len]) len++; if (len!=9) { is8=0; len++; } } retval=dl->StrSize; dl->StrSize+=len; dl->Strings=(char*)realloc(dl->Strings,dl->StrSize*sizeof(dl->Strings)); for (i=0; i<=len; i++) dl->Strings[retval+i]=name[i]; if (is8) dl->Strings[retval+8]=0; return retval; } int RelSort(const void *e1, const void *e2); int SecSort(const void *e1, const void *e2); void expandSection(TCoff *cf,int i,int addon) { int j,k; cf->Sections[i].s_size+=addon; cf->SectData[i]=(SCNDTA)realloc(cf->SectData[i],cf->Sections[i].s_size); //Here we will update all related information in the following sections for (j=i+1; jNumSect; j++) { for (k=0; kNumSym; k++) // move symbols if (cf->Symbols[k].e_scnum==j) cf->Symbols[k].e_value+=addon; for (k=0; kSections[j].s_nreloc; k++) cf->Relocs[j][k].r_vaddr+=addon; cf->Sections[j].s_vaddr+=addon; // move section } } void patchFrame(TCoff *cf) { int i; for (i=0; iNumSect; i++) { if (!strncmp(cf->Sections[i].s_name,".eh_fram",8)) { // special patch for .eh_frame section - it must end with LONG(0) expandSection(cf,i,4); *((unsigned long*)((char*)cf->SectData[i]+cf->Sections[i].s_size-4))=0; } } } TDlm *coff2dlm(TCoff *cf) { int i,s,dtaoff,j,max; Long *xsym; Byte *xrel; SYMENT *eh; DLMSYM *de; TDlm *dl=(TDlm*)malloc(sizeof(TDlm)); /* Number of sections will not change, so allocating */ dl->Base=0; dl->NumSect=cf->NumSect; dl->Sections=(DLMSCN*)malloc(sizeof(DLMSCN)*cf->NumSect); dl->SectData=(SCNDTA*)malloc(sizeof(SCNDTA)*cf->NumSect); /* Now working with symbols */ /* We will put only necessary symbols in output, so we need a "relocation table" for symbol indexes to patch relocs. As string table will be updated on fly will init it now */ dl->StrSize=0; dl->Strings=NULL; s=0; /* here we'll store current output index */ xsym=(Long*)malloc(sizeof(Long)*cf->NumSym); if (!xsym) err("memory error"); /* xrel will handle wether symbol is referenced */ xrel=(Byte*)malloc(sizeof(Byte)*cf->NumSym); if (!xrel) err("memory error"); memset(xrel,0,sizeof(Byte)*cf->NumSym); for (i=0; iNumSect; i++) for (j=0; jSections[i].s_nreloc; j++) xrel[cf->Relocs[i][j].r_symndx]=1; /* xsym will translate input index to output index. if 0 - symbols was ignored */ dl->Symbols=(DLMSYM*)malloc(sizeof(DLMSYM)*cf->NumSym); /* allocate for all for safe. usually we'll not use all of them. */ for (i=0; iNumSym; i++) { eh=cf->Symbols+i; /* we need in symbol table only symbols referenced in relocs and export symbols.*/ if (!xrel[i] && eh->e_sclass!=2) { xsym[i]=0; i+=eh->e_numaux; continue; } /* otherwise it's import or export symbol */ xsym[i]=s; de=dl->Symbols+(s++); de->e_value=eh->e_value; if (!eh->e_scnum) { if (!eh->e_value) de->e_flags=DLMSYM_IMPORT; else de->e_flags=DLMSYM_COMMON; } else if (eh->e_sclass==2) de->e_flags=DLMSYM_EXPORT; else if (!strncmp(cf->Sections[eh->e_scnum-1].s_name, eh->e.e_name,8)) { de->e_flags=DLMSYM_SECTION; } else de->e_flags=0; if (de->e_flags&DLMSYM_SECTION) de->e_name=DLMSYM_NONAME; else de->e_name=DlmAddStr(dl, /* Here we add symbol name to string table */ eh->e.e.e_zeroes?eh->e.e_name:cf->Strings+eh->e.e.e_offset, eh->e.e.e_zeroes?1:0); i+=eh->e_numaux; } dl->NumSym=s; /* Symbols done (strings also)*/ /* Now copying sections and counting number of relocs for later use */ s=0; for (i=0; iNumSect; i++) s+=cf->Sections[i].s_nreloc; /* This counts file offset of section data */ dtaoff=DLMHDRSZ+DLMSCNSZ*dl->NumSect+DLMSYMSZ*dl->NumSym+DLMRELSZ*s+dl->StrSize; dl->ScnOffs=dtaoff; for (i=0; iNumSect; i++) { memcpy(dl->Sections[i].s_name,cf->Sections[i].s_name,8); dl->Sections[i].s_vaddr=cf->Sections[i].s_vaddr; dl->Sections[i].s_size=cf->Sections[i].s_size; dl->Sections[i].s_scnptr=cf->SectData[i]?dtaoff:0; dl->Sections[i].s_flags=cf->Sections[i].s_flags; dl->SectData[i]=cf->SectData[i]; dtaoff+=cf->SectData[i]?dl->Sections[i].s_size:0; } dl->FSize=dtaoff; /* Now merging all relocs in one list as section makes no sense. We must not forget to change symbol indexes according to xsym table ( xsym[oldindex] is newindex )*/ dl->NumRel=s; dl->Relocs=(DLMREL*)malloc(sizeof(DLMREL)*dl->NumRel); s=0; for (i=0; iNumSect; i++) for (j=0; jSections[i].s_nreloc; j++,s++) { dl->Relocs[s].r_vaddr=cf->Relocs[i][j].r_vaddr; dl->Relocs[s].r_symndx=xsym[cf->Relocs[i][j].r_symndx]; dl->Relocs[s].r_flags=(cf->Relocs[i][j].r_type==6)?1:0; } /* Relocs done */ // calculating virtual size max=dl->Sections[0].s_size+dl->Sections[0].s_vaddr; for (i=1; iNumSect; i++) max=(max>dl->Sections[i].s_size+dl->Sections[i].s_vaddr)?max: dl->Sections[i].s_size+dl->Sections[i].s_vaddr; dl->VSize=max; /* Now creating linear section's space */ dl->Base=(char*)malloc(max); for (i=0; iNumSect; i++) { if (dl->SectData[i]) memcpy(dl->Base+dl->Sections[i].s_vaddr, dl->SectData[i],dl->Sections[i].s_size); else memset(dl->Base+dl->Sections[i].s_vaddr,0,dl->Sections[i].s_size); if (dl->Sections[i].s_size && dl->Sections[i].s_scnptr) dl->SectData[i]=dl->Base+dl->Sections[i].s_vaddr; else dl->SectData[i]=0; } /* Now we must sort some data in the DLM */ /* sorting relocation table by r_symndx */ qsort(dl->Relocs,dl->NumRel,DLMRELSZ,RelSort); return dl; } int RelSort(const void *e1, const void *e2) { int val=(int)(((DLMREL*)e1)->r_symndx) - (((DLMREL*)e2)->r_symndx); if (val < 0) return -1; else if (val > 0) return 1; else return ( (((DLMREL*)e1)->r_vaddr) > (((DLMREL*)e2)->r_vaddr) )?1:-1; } int SecSort(const void *e1, const void *e2) { return ( (((DLMSCN*)e1)->s_vaddr) > (((DLMSCN*)e2)->s_vaddr) )?1:-1; } void WriteDlm(TDlm *dl,char *fname,int appendflag) { int f,i; Long dtaoff; DLMHDR *fh; if (!appendflag) f=open(fname, O_RDWR|O_BINARY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR); else f=open(fname, O_RDWR|O_BINARY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR); fh=(DLMHDR*)malloc(DLMHDRSZ); fh->f_magic=DLM_MAGIC; fh->f_timdat=time(0); fh->f_nscns=dl->NumSect; fh->f_vsize=dl->VSize; fh->f_nreloc=dl->NumRel; fh->f_nsyms=dl->NumSym; fh->f_strsz=dl->StrSize; fh->f_flags=0; write(f,fh,DLMHDRSZ); /* File Header saved */ for (i=0; iNumSect; i++) write(f,dl->Sections+i,DLMSCNSZ); for (i=0; iNumSym; i++) write(f,dl->Symbols+i,DLMSYMSZ); for (i=0; iNumRel; i++) write(f,dl->Relocs+i,DLMRELSZ); write(f,dl->Strings,dl->StrSize); /* This counts file offset of section data */ dtaoff=DLMHDRSZ+DLMSCNSZ*dl->NumSect+DLMSYMSZ*dl->NumSym+ DLMRELSZ*dl->NumRel+dl->StrSize; for (i=0; iNumSect; i++) if (dl->SectData[i]) { /* printf("WRITE : Actual %d, must be %d, size %d\n", dtaoff,dl->Sections[i].s_scnptr,dl->Sections[i].s_size); */ write(f,dl->SectData[i],dl->Sections[i].s_size); /* put data in file */ dtaoff+=dl->Sections[i].s_size; } close(f); } void DestroyDlm(TDlm *dl) { free(dl->Relocs); free(dl->Symbols); free(dl->Sections); free(dl->Strings); free(dl->SectData); free(dl->Base); free(dl); } void AddSection(TDlm* dlm,char *name,unsigned long sz) { DLMSCN *sh; unsigned short idx,i; idx=dlm->NumSect++; dlm->Base=(char*)realloc(dlm->Base,dlm->VSize+sz); dlm->Sections=(DLMSCN*)realloc(dlm->Sections,DLMSCNSZ*dlm->NumSect); dlm->SectData=(SCNDTA*)realloc(dlm->SectData,sizeof(SCNDTA)*dlm->NumSect); dlm->SectData[idx]=dlm->Base+dlm->VSize; sh=dlm->Sections+idx; strncpy(sh->s_name,name,8); sh->s_vaddr=dlm->VSize; sh->s_size=sz; sh->s_scnptr=dlm->FSize; sh->s_flags=0; dlm->VSize+=sz; dlm->FSize+=sz+DLMSCNSZ; for (i=0; iNumSect; i++) if (dlm->Sections[i].s_scnptr) dlm->Sections[i].s_scnptr+=DLMSCNSZ; } void AddSymbol(TDlm *dlm,char *name, char *fname) { unsigned long i,f,sz,stroffs; unsigned long val; DLMSYM *eh; val=dlm->VSize; if (!quite) printf("Adding symbol '%s' with the contents of file '%s' ...\n",name,fname); f=open(fname,O_BINARY|O_RDWR, S_IRUSR|S_IWUSR); if (f==-1) { printf("filename=%s ",fname); err("can't open file"); } sz=filelength(f); if (sz==-1) err("can't get file length"); AddSection(dlm,".extra",sz); read(f,dlm->Base+val,sz); close(f); stroffs=DlmAddStr(dlm, name,0); dlm->Symbols=(DLMSYM*)realloc(dlm->Symbols,DLMSYMSZ*(dlm->NumSym+1)); eh=dlm->Symbols+(dlm->NumSym++); eh->e_name=stroffs; eh->e_value=val; eh->e_flags=DLMSYM_EXPORT; sz=DLMSYMSZ+strlen(name)+1; for (i=0; iNumSect; i++) if (dlm->Sections[i].s_scnptr) dlm->Sections[i].s_scnptr+=sz; dlm->FSize+=sz; } void DelSection(TDlm *dlm,unsigned short scnum) { unsigned long i,size,vaddr; size=dlm->Sections[scnum].s_size; vaddr=dlm->Sections[scnum].s_vaddr; dlm->VSize-=size; if (scnumNumSect-1) memmove(dlm->Base+vaddr,dlm->Base+vaddr+size,dlm->VSize-vaddr); for (i=0; iNumSym; i++) if (dlm->Symbols[i].e_flags!=DLMSYM_IMPORT && dlm->Symbols[i].e_flags!=DLMSYM_COMMON && dlm->Symbols[i].e_value>=vaddr) dlm->Symbols[i].e_value-=size; dlm->NumSect--; for (i=scnum; iNumSect; i++) { dlm->Sections[i]=dlm->Sections[i+1]; dlm->Sections[i].s_vaddr-=size; if (dlm->Sections[i].s_scnptr) dlm->Sections[i].s_scnptr-=size; if ((dlm->SectData[i]=dlm->SectData[i+1])) dlm->SectData[i]-=size; } for (i=0; iNumSect; i++) if (dlm->Sections[i].s_scnptr) dlm->Sections[i].s_scnptr-=DLMSCNSZ; dlm->FSize-=DLMSCNSZ+size; } void DelSymbol(TDlm *dlm,char *name) { unsigned long i,j,symndx=0xFFFFFFFF,strsz,scnum; DLMSYM *eh=0; if (!quite) printf("Removing symbol '%s' ...\n",name); /* Find symbol */ for (i=0; iNumSym; i++) if (!strcmp(dlm->Strings+dlm->Symbols[i].e_name,name)) { eh=dlm->Symbols+i; symndx=i; break; } if (!eh) { printf("Can't find symbol '%s' in DLM\n",name); return; } /* Find appropriate .extra section */ for (i=0; iNumSect; i++) { if (!strncmp(".extra",dlm->Sections[i].s_name,8) && dlm->Sections[i].s_vaddr==eh->e_value) break; } if (i==dlm->NumSect) { printf("Symbol %s is not in .extra section\n",name); return; } scnum=i; /* Now symndx is symbol index and scnum is section index */ /* Removing symbol name from string table */ strsz=strlen(name)+1; for (j=eh->e_name; jStrSize-strsz; j++) dlm->Strings[j]=dlm->Strings[j+strsz]; for (i=0; iNumSym; i++) if (dlm->Symbols[i].e_name>eh->e_name && dlm->Symbols[i].e_name!=DLMSYM_NONAME) dlm->Symbols[i].e_name-=strsz; dlm->StrSize-=strsz; /* Removing symbol from symbol table */ for (j=symndx; jNumSym-1; j++) dlm->Symbols[j]=dlm->Symbols[j+1]; for (j=0; jNumRel; j++) if (dlm->Relocs[j].r_symndx>symndx) dlm->Relocs[j].r_symndx--; dlm->NumSym--; DelSection(dlm,scnum); for (i=0; iNumSect; i++) if (dlm->Sections[i].s_scnptr) dlm->Sections[i].s_scnptr-=DLMSYMSZ+strsz; dlm->FSize-=DLMSYMSZ+strsz; } void AddAutoLoad(TDlm* dlm, char *name) { unsigned long sz; unsigned long val; val=dlm->VSize; if (!quite) printf("Adding Auto-Load DLM '%s' ...\n",name); sz=strlen(name)+1; AddSection(dlm,".aload",sz); memcpy(dlm->Base+val,name,sz); } void AddDAL(TDlm *dlm, char *name) { FILE *f; f=fopen(name,"r"); if (f==NULL) err("unable open export file"); while (fgets(buf,255,f)) { buf[strcspn(buf,"\x0d\x0a")]=0; AddAutoLoad(dlm,buf); } fclose(f); } void DelAutoLoad(TDlm* dlm, char *name) { unsigned long i; /* Find appropriate .extra section */ for (i=0; iNumSect; i++) if (!strncmp(".aload",dlm->Sections[i].s_name,8) && !strcmp(dlm->Base+dlm->Sections[i].s_vaddr,name)) break; if (i==dlm->NumSect) { printf("No such Auto-Load entry '%s' in DLM\n",name); return; } DelSection(dlm,i); } void DumpExport(TDlm *dlm,char *exp) { int i; FILE *f; f=fopen(exp,"w"); if (f==NULL) err("unable open dump export file"); for (i=0; iNumSym; i++) if (dlm->Symbols[i].e_flags&(DLMSYM_EXPORT|DLMSYM_COMMON)) fprintf(f,"%s\n",dlm->Strings+dlm->Symbols[i].e_name); fclose(f); } void DumpImport(TDlm *dlm,char *imp) { int i; FILE *f; f=fopen(imp,"w"); if (f==NULL) err("unable open dump export file"); for (i=0; iNumSym; i++) if (dlm->Symbols[i].e_flags&DLMSYM_IMPORT) fprintf(f,"%s\n",dlm->Strings+dlm->Symbols[i].e_name); fclose(f); } void UpdateExport(TDlm *dlm,char *exp) { int i; FILE *f; for (i=0; iNumSym; i++) dlm->Symbols[i].e_flags&=~DLMSYM_EXPORT; f=fopen(exp,"r"); if (f==NULL) err("unable open export file"); while (fgets(buf,255,f)) { buf[strcspn(buf,"\x0d\x0a")]=0; for (i=0; iNumSym; i++) if (dlm->Symbols[i].e_flags!=DLMSYM_IMPORT && dlm->Symbols[i].e_flags!=DLMSYM_SECTION) if (!strcmp(dlm->Strings+dlm->Symbols[i].e_name,buf)) dlm->Symbols[i].e_flags|=DLMSYM_EXPORT; } fclose(f); } void DumpExportWithDLM(TDlm *dlm,char *exp) { int i; FILE *f; f=fopen(exp,"a"); if (f==NULL) err("unable open dump export file"); for (i=0; iNumSym; i++) if (dlm->Symbols[i].e_flags&DLMSYM_EXPORT) fprintf(f,"%s,%s\n",dlm->Strings+dlm->Symbols[i].e_name,dlm->filename); fclose(f); } void GenerateDAL(TDlm *dlm,char *out,char *lst) { int i,j,numdlms=0; FILE *f; char *sym,*dlmname; char **dlmlst=0; f=fopen(lst,"r"); if (f==NULL) err("unable open export file"); while (fgets(buf,255,f)) { sym=strtok(buf,",\x0d\x0a"); dlmname=strtok(0,",\x0d\x0a"); if (!sym || !dlmname) continue; for (i=0; iNumSym; i++) if (dlm->Symbols[i].e_flags==DLMSYM_IMPORT) if (!strcmp(dlm->Strings+dlm->Symbols[i].e_name,sym)) { if (numdlms) { for (j=0; j