pike.git / NT / tools / pntld

version» Context lines:

pike.git/NT/tools/pntld:1: + #!/usr/local/bin/pike    -  + /* Partial linker for COFF files, written by Fredrik Hubinette 2000 */ +  + class Reloc + { +  Symbol sym; +  int loc; +  int type; + }; +  + class Section + { +  string name; +  string data; +  array(Reloc) relocs; +  +  int virtual_size; +  int characteristics; +  +  int section_number; + }; +  + class Symbol + { +  string name; +  int value; +  Section section; +  int type; +  int cls; +  array(Symbol) aux; + }; +  +  + mapping(string:Symbol) global_symbols=([]); + array(Section) global_sections=({}); + array(string) global_directives=({}); +  + class Linker + { +  string ret=""; +  string stringtable=""; +  string symboltable=""; +  string sectiondata=""; +  string sectiontable=""; +  int num_symbols; +  +  int base; +  mapping(Symbol:int) symbol_to_number=([]); +  +  mapping(string:int) stringtablecache=([]); +  int add_string(string s) +  { +  int pos; +  s+="\0"; +  if(pos=stringtablecache[s]) return pos-1; +  pos=search(stringtable, s); +  if(pos == -1) +  { +  pos=strlen(stringtable); +  stringtable+=s; +  } +  stringtablecache[s]=pos-1; +  return pos; +  } +  +  string add_sym_name(string s) +  { +  if(strlen(s) <= 8) +  return s + "\0"*(8-strlen(s)); +  return sprintf("%-4c%-4c",0,add_string(s)); +  } +  +  int add_symbol(Symbol s) +  { + #ifdef DEBUG +  werror("Encoding symbol named: %s\n",s->name); + #endif +  if(symbol_to_number[s]) +  return symbol_to_number[s]-1; +  +  num_symbols++; +  symboltable+=sprintf("%s%-4c%-2c%-2c%c%c", +  add_sym_name(s->name), +  s->value, +  s->section ? s->section->section_number + 1 : 0, +  s->type, +  s->cls, +  0); /* aux symbols not supported */ +  symbol_to_number[s]=sizeof(symbol_to_number)+1; +  return symbol_to_number[s]-1; +  } +  +  +  string out(array(Section) sections, +  array(Symbol) exports) +  { +  int secnum; +  base=20 /*coff*/ + +  sizeof(sections) * 40; +  +  foreach(sections, Section s) +  s->section_number = secnum++; +  +  foreach(sections, Section s) +  { + #ifdef DEBUG +  werror("Encoding section named: %s\n",s->name); + #endif +  sectiontable+= +  sprintf("%s%-4c%-4c%-4c%-4c%-4c%-4c%-2c%-2c%-4c", +  add_sym_name(s->name), +  s->virtual_size, +  0, /* virtual address */ +  s->data ? sizeof(s->data) : 0, +  base + strlen(sectiondata), +  base + strlen(sectiondata) + (s->data ? sizeof(s->data) : 0), +  0, /* no linenums */ +  sizeof(s->relocs), +  0, +  s->characteristics); +  sectiondata+=s->data; +  foreach(s->relocs, Reloc r) +  sectiondata+=sprintf("%-4c%-4c%-2c", +  r->loc, +  add_symbol(r->sym), +  r->type); +  } +  +  foreach(exports, Symbol s) add_symbol(s); +  +  return +  sprintf("%-2c%-2c%-4c%-4c%-4c%-2c%-2c" /* coff */ +  "%s%s%s%s" /* the rest */ , +  +  /* coff */ +  0x14c, /* Intel x86 */ +  sizeof(sections), +  time(), +  base+strlen(sectiondata), +  num_symbols, +  0, /* opt header size */ +  0, /* no character */ +  +  sectiontable, +  sectiondata, +  symboltable, +  stringtable); +  } +  + } +  + mapping machine_table = ([ +  0:"Unknown", +  0x14c:"Intel x86", +  ]); +  + class Bitfield + { +  array(string) names; +  +  string desc(int num) +  { +  int x; +  array(string) ret=({}); +  while(num && x<sizeof(names)) +  { +  if(1 & num) +  ret+=({ names[x] }); +  x++; +  num>>=1; +  num&=0x7fffffff; +  } +  if(!sizeof(ret) || num) +  ret+=({ sprintf("%x",num << x) }); +  +  return ret*" | "; +  } +  void create(string ... n) +  { +  names=n; +  } + } +  + Bitfield character_descriptor=Bitfield( +  "RELOCS_STRIPPED", +  "EXECUTABLE_IMAGE", +  "LINE_NUMS_STRIPPED", +  "LOCAL_SYMS_STRIPPED", +  "AGGRESSIVE_WS_TRIM", +  "LARGE_ADDRESS_AWARE", +  "16BIT_MACHINE", +  "BYTES_REVERSED_LO", +  "32BIT_MACHINE", +  "DEBUG_STRIPPED", +  "REMOVABLE_RUN_FROM_SWAP", +  "FILE_SYSTEM", +  "DLL", +  "UP_SYSTE_MONLY", +  "BYTES_REVERSED_HI" ); +  + Bitfield section_character_descriptor=Bitfield( +  "DSECT", +  "NOLOAD", +  "GROUP", +  "TYPE_NO_PAD", +  "*COPY", +  "*CODE", +  "INITED_DATA", +  "UNINITED_DATA", +  "LNK_OTHER", +  "LNK_INFO", +  "TYPE_OVER", +  "LNK_REMOVE", +  "LNK_COMDAT", +  "-", +  "-", +  "MEM_FARDATA", +  "*MEM_PURGEABLE", +  "*MEM_16BIT", +  "*MEM_LOCKED", +  "*MEM_PRELOAD", +  "ALIGN_1", +  "ALIGN_2", +  "ALIGN_4", +  "ALIGN_8", +  "LNK_NRELOC_OVFL", +  "MEM_DISCARDABLE", +  "MEM_NOT_CACHED", +  "MEM_NOT_PAGED", +  "MEM_SHARED", +  "MEM_EXECUTE", +  "MEM_READ", +  "MEM_WRITE", + ); +  + #define CHR_LINK_INFO 0x200 + #define CHR_LINK_REMOVE 0x800 + #define CHR_LINK_ALIGN_1 0x100000 + #define CHR_LINK_MEM_DISCARDABLE 0x2000000 +  +  + class dumpfile + { +  string filename; +  string data; +  int base; +  +  int stringtable; +  int symboltable, numsymbols; +  int sections, numsections; +  +  array(Symbol) file_symbols; +  array(Section) file_sections; +  +  void hexdump(int pos) +  { +  string x=data[pos..pos+128]; +  foreach(x/8,string line) +  { +  write("%06x: %{%02x %} %O\n",pos,values(line),line); +  pos+=strlen(x); +  } +  } +  +  int i4(int pos) +  { +  pos+=base; +  return data[pos] | (data[pos+1]<<8) | (data[pos+2]<<16) | (data[pos+3]<<24); +  } +  +  int i8(int pos) +  { +  pos+=base; +  return data[pos] | (data[pos+1]<<8) | (data[pos+2]<<16) | (data[pos+3]<<24) | +  (data[pos+4]<<32) | (data[pos+5]<<40) | (data[pos+6]<<48) | (data[pos+7]<<56); +  +  } +  +  int i1(int pos) +  { +  pos+=base; +  return data[pos]; +  } +  +  int i2(int pos) +  { +  pos+=base; +  return data[pos] | (data[pos+1]<<8); +  } +  +  string nulltermstring(int p) +  { +  p+=base; +  int end=search(data,"\0",p); +  return data[p..end-1]; +  } +  +  string range(int from, int len) +  { +  from+=base; +  return data[from..from+len-1]; +  } +  +  string getCOFFstring(int pos) +  { +  if(!i4(pos)) +  { +  return nulltermstring(stringtable + i4(pos+4)); +  } +  return ( range(pos,8)/"\0" )[0]; +  } +  +  string decodeRelocType(int t) +  { +  switch(t) +  { +  case 0: return "absolute"; +  case 1: return "dir16"; +  case 2: return "rel16"; +  case 6: return "dir32"; +  case 7: return "dir32nb"; +  case 9: return "seg12"; +  case 10: return "sect"; +  case 11: return "secrel"; +  case 20: return "rel32"; +  default: return sprintf("<%d>",t); +  } +  } +  +  +  array(Reloc) dumpRelocs(int pos, int num_relocs) +  { +  array(Reloc) ret=({}); +  for(int e=0;e<num_relocs;e++) +  { + #ifdef DEBUG +  write(" [ %08x = symbol(%5d, %8s) = %s]\n", +  i4(pos), +  i4(pos+4), +  decodeRelocType(i2(pos+8)), +  getsymbolname(i4(pos+4))); + #endif +  Reloc r=Reloc(); +  r->loc=i4(pos); +  r->sym=file_symbols[i4(pos+4)]; +  r->type=i2(pos+8); +  pos+=10; +  +  ret+=({r}); +  } +  +  return ret; +  } +  +  int translatevaddr(int addr) +  { +  int pos=sections; +  for(int e=0;e<numsections;e++) +  { +  int start=i4(pos+12); +  if(addr >= start && addr < start + i4(pos+8)) +  { + // write("--start=%d-%d-sect=%d--\n",start,i4(pos+20),e); +  return addr - start + i4(pos+20); +  } +  pos+=40; +  } +  return -1; +  } +  +  void dumpSECTS() +  { +  int pos=sections; + #ifdef DEBUG +  write("\n-=SECTIONS=-\n"); + #endif +  for(int e=0;e<numsections;e++) +  { +  string caracter; + #ifdef DEBUG +  write("\n"); +  write("Name : %s\n",getCOFFstring(pos)); +  write("Virtual Size : %x\n",i4(pos+8)); +  write("Virtual Addres : %x\n",i4(pos+12)); +  write("RAW data size : %x\n",i4(pos+16)); +  write("Ptr2RawData : %x\n",i4(pos+20)); +  write("Ptr2Relocs : %x\n",i4(pos+24)); +  write("Ptr2Linenums : %x\n",i4(pos+28)); +  write("num relocs : %x\n",i2(pos+32)); +  write("num linenums : %x\n",i2(pos+34)); +  write("characteristics : %s\n", +  caracter=section_character_descriptor->desc(i4(pos+36))); + #endif +  +  file_sections[e]->name=getCOFFstring(pos); +  file_sections[e]->data=range(i4(pos+20),i4(pos+16)); +  file_sections[e]->virtual_size=i4(pos+8);; +  file_sections[e]->characteristics=i4(pos+36); +  file_sections[e]->relocs=dumpRelocs(i4(pos+24), i2(pos+32)); +  +  +  if(file_sections[e]->characteristics & CHR_LINK_INFO) +  { +  foreach(file_sections[e]->data/" ", string directive) +  if(search(global_directives, directive) == -1) +  global_directives+=({ directive }); +  +  } +  else +  { +  global_sections+=({ file_sections[e] }); +  } + #ifdef DEBUG +  if(search(caracter,"LNK_INFO")!=-1) +  write("%O\n",range(i4(pos+20),i4(pos+16))); + #endif +  pos+=40; +  } +  } +  +  string getvirtualname(int vaddr) +  { +  int x=translatevaddr(vaddr); +  if(x==-1) return sprintf("<out of bounds %x>",vaddr); +  return nulltermstring(x); +  } +  +  /* Symbol table stuff */ +  string decodeCOFFtypeLSB(int t) +  { +  switch(t) +  { +  case 0: return "null"; +  case 1: return "void"; +  case 2: return "char"; +  case 3: return "short"; +  case 4: return "int"; +  case 5: return "long"; +  case 6: return "float"; +  case 7: return "double"; +  case 8: return "struct"; +  case 9: return "union"; +  case 10: return "enum"; +  case 11: return "MOE"; +  case 12: return "byte"; +  case 13: return "word"; +  case 14: return "uint"; +  case 15: return "dword"; +  default: return sprintf("<%x>",t); +  } +  } +  +  string decodeCOFFtype(int t) +  { +  switch(t >> 4) +  { +  case 0: return decodeCOFFtypeLSB(t); +  case 1: return decodeCOFFtypeLSB(t & 15) + "*"; +  case 2: return decodeCOFFtypeLSB(t & 15) + "()"; +  case 3: return decodeCOFFtypeLSB(t & 15) + "[]"; +  default: return sprintf("<%x>",t); +  } +  } +  +  string decodeCOFFstorageclass(int t) +  { +  switch(t) +  { +  case -1: case 255: return "End of function"; +  case 0: return "null"; +  case 1: return "automatic"; +  case 2: return "external"; +  case 3: return "static"; +  case 4: return "register"; +  case 5: return "external def"; +  case 6: return "label"; +  case 7: return "undef label"; +  case 8: return "member of struct"; +  case 9: return "argument"; +  case 10: return "struct tag"; +  case 11: return "member of union"; +  case 12: return "union tag"; +  case 13: return "type def"; +  case 14: return "undef static"; +  case 15: return "enum tag"; +  case 16: return "member of enum"; +  case 17: return "register param"; +  case 18: return "bit field"; +  case 100: return "block"; +  case 101: return "function"; +  case 102: return "end of struct"; +  case 103: return "file"; +  case 104: return "section"; +  case 105: return "weak external"; +  default: return sprintf("<%x>",t); +  } +  } +  +  string getsymbolname(int x) +  { +  if(x >= numsymbols) return sprintf("Out of bound (%d)",x); +  return getCOFFstring(symboltable + x * 18); +  } +  +  void dumpSymTable() +  { +  array ret=allocate(numsymbols); +  int pos=symboltable; +  for(int e=0;e<numsymbols;e++) +  { +  int aux; + #ifdef DEBUG + #if 1 +  write("[%5d] %08x %4x %-9s %-9s %x %s\n", +  e, +  i4(pos+8), +  i2(pos+12), +  decodeCOFFtype(i2(pos+14)), +  decodeCOFFstorageclass(i1(pos+16)), +  aux=i1(pos+17), +  getCOFFstring(pos)); +  + #else +  write("[%5d] name : %s\n",e,getCOFFstring(pos)); +  write("[%5d] value : %x\n",e,i4(pos+8)); +  write("[%5d] secnum : %d\n",e,i2(pos+12)); +  write("[%5d] type : %s\n",e,decodeCOFFtype(i2(pos+14))); +  write("[%5d] Storage class : %s\n",e,decodeCOFFstorageclass(i1(pos+16))); +  write("[%5d] Num Aux syms : %x\n",e,aux=i1(pos+17)); + #endif + #endif +  string name=getCOFFstring(pos); +  int cls=i1(pos+16); +  int sect=i2(pos+12); +  int value=i4(pos+8); +  int type=i2(pos+14); +  if(sect > 32768) sect=65536-sect; +  +  Symbol s=Symbol(); +  s->name=name; +  s->value=value; +  s->section=sect>0 ? file_sections[sect-1] : 0; +  s->type=type; +  s->cls=cls; +  s->aux=0; +  + #define COFFSYM_external 2 +  +  switch(cls) +  { +  case COFFSYM_external: +  if(global_symbols[name]) +  { +  s=global_symbols[name]; +  if(s->section && sect > 0) +  werror("%s: Warning: Symbol %s defined twice.\n", +  filename, +  name); +  } +  +  if(sect > 0) +  { +  s->section = file_sections[sect-1]; +  s->value = value; +  s->type = type; +  } +  global_symbols[name]=s; +  } +  file_symbols[e]=s; +  +  aux=i1(pos+17); +  +  pos+=18; +  for(int a=0;a<aux;a++) +  { +  pos+=18; +  e++; +  } +  } +  } +  +  void dumpCOFF(int pos) +  { + #ifdef DEBUG +  write("-=COFF HEADER=-\n"); + #endif +  sscanf(reverse(range(pos,20)), +  "%2c%2c%4c%4c%4c%2c%2c", +  int characteristics, +  int sizeofoptheader, +  numsymbols, +  symboltable, +  int timestamp, +  numsections, +  int machine); +  + #ifdef DEBUG +  write("Machine : %s\n",machine_table[machine] || sprintf("%x",machine)); +  write("Sections : %x\n",numsections); +  write("Timesamp : %s",ctime(timestamp)); +  write("Symbol Table: %x\n",symboltable); +  write("Symbols : %d\n",numsymbols); +  write("Optheadsize : %x\n",sizeofoptheader); +  write("Character : %s\n",character_descriptor->desc(characteristics)); + #endif +  +  stringtable = symboltable + numsymbols*18; +  sections=pos+20+sizeofoptheader; +  +  file_symbols=allocate(numsymbols); +  file_sections=allocate(numsections,Section)(); +  +  dumpSymTable(); +  dumpSECTS(); +  } +  +  int dumpPE(int pos) +  { + #ifdef DEBUG +  write("Potential PE identifier at 0x%x ... ",pos); + #endif +  if(data[pos..pos+3]!="PE\0\0") +  { + #ifdef DEBUG +  write("No.\n"); + #endif +  return 0; +  } else { + #ifdef DEBUG +  write("Yes.\n"); + #endif +  } +  dumpCOFF(pos+4); +  return 1; +  } +  +  void dumpArchive(int pos) +  { +  while(pos < strlen(data)) +  { +  string name=range(pos,16); +  int size = (int) range(pos+48,10); +  + #ifdef DEBUG +  write("\n"); +  write("# name: %s\n",name); +  write("# date: %s\n",ctime( (int) range(pos+16,12) ) ); +  write("# uid : %s\n",range(pos+28,6)); +  write("# gid : %s\n",range(pos+34,6)); +  write("# mode: %s\n",range(pos+40,8)); +  write("# size: %s\n",range(pos+48,10)); + #endif +  +  if(name[0]!='/') +  dumpfile(data, pos+60,0,name); +  +  pos+=60; +  pos+=(size+1)&~1; +  } +  } +  +  void create(string d, void|int p, void|int len, void|string f) +  { +  base=p; +  data=d; +  filename=f; +  if(!len) len=strlen(d)-base; +  +  if(range(0,8) == "!<arch>\n") +  { + #ifdef DEBUG +  write("Archive!\n"); + #endif +  dumpArchive(8); +  }else{ +  if(len >=0x40 && !dumpPE(i4(0x3c))) +  { +  dumpCOFF(0); +  } +  } +  } + } +  + int main(int argc, array(string) argv) + { +  int strip=0; +  string output="a.out"; + // werror("%O\n",argv); +  werror("Pike Win32 partial linker.\n" +  "$Id: pntld,v 1.1 2000/12/23 07:19:49 hubbe Exp $\n" +  "Written by Fredrik Hubinette 2000\n"); +  +  foreach(Getopt.find_all_options(argv,aggregate( +  ({"output",Getopt.HAS_ARG,({"-o"})}), +  ({"R",Getopt.HAS_ARG,({"-R"})}), +  ({"L",Getopt.HAS_ARG,({"-L"})}), +  ({"l",Getopt.HAS_ARG,({"-l"})}), +  ({"S",Getopt.NO_ARG,({"-S"})}), +  ({"ignore","Getopt.HAS_ARG",({"-r","-i","-s","-g","-B","-W"})}), +  )),array opt) +  { +  switch(opt[0]) +  { +  case "S": strip++; break; +  +  case "R": +  case "L": +  global_directives|=({ "-?rpath:"+opt[1] }); +  break; +  +  case "l": +  switch(opt[1]) +  { +  case "c": case "m": break; +  default: +  /* FIXME: +  * search for *.lib files and link them 'statically' +  * if found. +  */ +  global_directives|=({ "-lib:"+opt[1] }); +  } +  break; +  +  case "output": +  output=opt[1]; +  break; +  } +  } +  +  argv=Getopt.get_args(argv); +  +  foreach(argv[1..],string file) +  dumpfile(Stdio.read_file(file),0,0,file+":"+file); +  +  if(strip) +  { +  global_sections=Array.filter(global_sections, +  lambda(Section s) +  { +  return !(s->characteristics & CHR_LINK_MEM_DISCARDABLE); +  }); +  } +  +  if(sizeof(global_directives)) +  { +  Section s=Section(); +  s->name=".drectve"; +  s->data=global_directives * " "; +  s->characteristics = CHR_LINK_INFO | CHR_LINK_REMOVE | CHR_LINK_ALIGN_1; +  s->relocs=({}); +  +  global_sections= ({s}) + global_sections; +  } +  +  rm(output); +  Stdio.write_file(output, +  Linker()->out(global_sections, +  values(global_symbols))); +  exit(0); + }   Newline at end of file added.