dxegen.pp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. {
  2. $Id$
  3. Copyright (C) 1995 Charles Sandmann ([email protected])
  4. This software may be freely distributed with above copyright, no warranty.
  5. Based on code by DJ Delorie, it's really his, enhanced, bugs fixed.
  6. DXEGEN converts COFF object files to .DXE files that can be loaded and
  7. relocated runtime. See (1.0.6+) manual for more details.
  8. Pascal translation, improvements, enhancements
  9. (C) 2001 by Marco van de Voort (Free Pascal member).
  10. }
  11. Uses Strings,DxeLoad,Coff,Dos;
  12. {$inline on}
  13. Const
  14. DirSep = System.DirectorySeparator;
  15. Tempname= 'dxe__tmp.o';
  16. { This next function is needed for cross-compiling when the machine
  17. isn't little-endian like the i386 }
  18. Type csize_t = cardinal;
  19. Procedure dosswap(vdata:pointer;Const pattern:String);
  20. { interpretive way of changing structures to bigendian.
  21. Pattern contains the structures. l (32-bit) and s (16-bit) will be swapped,
  22. a char between 1 and 9 skips that much bytes)
  23. Excellent candidate to be converted to something generic that inlines and
  24. isn't interpretive. Until generics, this is the only reusable way.
  25. }
  26. {$ifdef BigEndian}
  27. Var data : pbyte;
  28. c : byte;
  29. i,j : longint;
  30. {$endif}
  31. Begin
  32. {$ifdef BigEndian}
  33. I := 1;
  34. j := length(pattern);
  35. data := pbyte(vdata);
  36. while I< = j Do
  37. Begin
  38. Case Pattern[i] Of
  39. '1'..'9' : inc(data,ord(pattern[i])-ord('0'));
  40. 's' :
  41. Begin
  42. c := data[1];
  43. data[1] := data[0];
  44. data[0] := c;
  45. inc(data,2);
  46. End;
  47. 'l' :
  48. Begin
  49. c := data[3];
  50. data[3] := data[0];
  51. data[0] := c;
  52. c := data[1];
  53. data[1] := data[2];
  54. data[2] := c;
  55. inc(data,4);
  56. // bswap (Data) ?
  57. End
  58. Else
  59. inc(data);
  60. End;
  61. inc(i);
  62. End;
  63. {$endif}
  64. End;
  65. Var blaat : pointer;
  66. Procedure exit_cleanup;
  67. Var f: file;
  68. Begin
  69. assign(f,tempname);
  70. {$I-}
  71. erase(f);
  72. {$I+}
  73. exitproc := blaat;
  74. End;
  75. Var
  76. Errors : Longint;
  77. Bss_start : Cardinal; {type "unsigned" ?}
  78. fh : FILHDR;
  79. Input_f,
  80. Output_F : file;
  81. Sc : SCNHDR;
  82. Data,
  83. Strngs : PChar; {strings is not reserved, but not wise to use in C translations}
  84. Sym : ^SYMENT;
  85. Relocs : pRELOC;
  86. Strsz : Longint;
  87. I : csize_t;
  88. Dh : dxe_header;
  89. Command,
  90. Param,
  91. Libdir : ansistring;
  92. Name : pchar;
  93. Tmp : array[0..8] Of char;
  94. Written : Word;
  95. Function fixrelocs(i:longint): preloc; {$ifdef HASINLINE}inline;{$endif}
  96. Begin
  97. fixrelocs := preloc(longint(relocs)+i*SIZEOF(reloc));
  98. End;
  99. Begin
  100. Errors := 0;
  101. Bss_start := 0;
  102. If paramcount<3 Then
  103. Begin
  104. Writeln('Usage: dxegen output.dxe symbol input.o [input2.o ... -lgcc -lc]');
  105. Halt(1);
  106. End;
  107. Assign (input_f,paramstr(3));
  108. Filemode := 0;
  109. {$I-}
  110. Reset(input_f,1);
  111. {$I+}
  112. If IOResult<>0 Then
  113. Begin
  114. Writeln('File: ',ParamStr(3),' couldn''t be opened');
  115. halt(1);
  116. End;
  117. {Read the COFF .O fileheader}
  118. Blockread(input_f,fh,FILHSZ);
  119. dosswap(@fh,'sslllss');
  120. If (fh.f_nscns <>1) And (paramcount>3) Then
  121. Begin
  122. Close(input_f);
  123. {$ifdef DXE_LD}
  124. command := DXE_LD;
  125. {$else}
  126. command := 'ld';
  127. {$endif}
  128. param := '-X -S -r -o '+tempname+' -L';
  129. libdir := getenv('DXE_LD_LIBRARY_PATH');
  130. If libdir<>'' Then
  131. param := param+libdir
  132. Else
  133. Begin
  134. libdir := getenv('DJDIR'); {FPCDIR ?}
  135. If libdir='' Then
  136. Begin
  137. Writeln('Error: neither DXE_LD_LIBRARY_PATH nor DJDIR are set in environment');
  138. Halt(1);
  139. End;
  140. param := param+libdir+dirsep+'lib';
  141. End;
  142. For i:= 3 To ParamCount Do
  143. param := param+' '+paramstr(i);
  144. param := param+' -T dxe.ld ';
  145. Writeln('Executing: "',Command,' ',param,'"');
  146. Exec(Command,Param);
  147. Errors := DosExitCode;
  148. If Errors<>0 Then
  149. Begin
  150. Writeln('Dos returned errorcode: ',Errors);
  151. Halt(Errors);
  152. End;
  153. Assign(input_f,tempname);
  154. FileMode := 0;
  155. {$I-}
  156. Reset(Input_f,1);
  157. {$I+}
  158. If IOresult<>0 Then
  159. Begin
  160. Close(input_f);
  161. Writeln('couldn''t open file: '+tempname);
  162. halt(1);
  163. End
  164. Else
  165. Begin
  166. blaat := exitproc;
  167. exitproc := @exit_cleanup;
  168. End;
  169. blockread(input_f,fh,FILHSZ);
  170. dosswap(@fh, 'sslllss');
  171. If (fh.f_nscns <>1) Then
  172. Begin
  173. Close(input_f);
  174. Writeln('Error: input file has more than one section; use -M for map');
  175. halt(1);
  176. End;
  177. End;
  178. seek(input_f,FilePos(Input_f)+fh.f_opthdr);
  179. BlockRead(input_f,sc,SCNHSZ);
  180. dosswap(@sc, '8llllllssl');
  181. dh.magic := DXE_MAGIC;
  182. dh.symbol_offset := -1;
  183. dh.element_size := sc.s_size;
  184. dh.nrelocs := sc.s_nreloc;
  185. Getmem(Data,sc.s_size);
  186. Seek(input_f,sc.s_scnptr);
  187. BlockRead(input_f,data^, sc.s_size);
  188. Getmem(sym,sizeof(SYMENT)*fh.f_nsyms);
  189. Seek(input_f,fh.f_symptr);
  190. Blockread(input_f,sym^,fh.f_nsyms*SYMESZ);
  191. Blockread(input_f,strsz,4);
  192. Dosswap(@strsz,'l');
  193. Getmem(Strngs,strsz);
  194. Blockread(input_f,strngs[4],strsz-4);
  195. plongint(strsz)[0] := 0; // {?}
  196. For i:=0 To fh.f_nsyms-1 Do
  197. Begin
  198. If (sym[i].e.e.e_zeroes<>0) Then
  199. Begin
  200. dosswap(@sym[i], '8lscc');
  201. move(sym[i].e.e_name,tmp,8);
  202. tmp[8] := #0;
  203. name := @tmp;
  204. End
  205. Else
  206. Begin
  207. dosswap(@sym[i], 'lllscc');
  208. name := strngs + sym[i].e.e.e_offset;
  209. End;
  210. If (sym[i].e_scnum = 0) Then
  211. Begin
  212. Writeln('Error: object contains unresolved external symbols (', name,')');
  213. inc(errors);
  214. End;
  215. If (strlcomp(name, argv[2], strlen(argv[2])) = 0) Then
  216. Begin
  217. If (dh.symbol_offset <> -1) Then
  218. Begin
  219. Writeln('Error: multiple symbols that start with ',paramstr(2),' (',name,
  220. ')!');
  221. Inc(errors);
  222. End;
  223. dh.symbol_offset := sym[i].e_value;
  224. End
  225. Else If (strcomp(name, '.bss') = 0) And (bss_start=0) Then
  226. Begin
  227. bss_start := sym[i].e_value;
  228. Fillchar(data[bss_start], sc.s_size - bss_start,#0);
  229. End;
  230. Inc(i,sym[i].e_numaux);
  231. End;
  232. If (dh.symbol_offset = -1) Then
  233. Begin
  234. Writeln('Error: symbol ',argv[2],' not found!');
  235. Inc(Errors);
  236. End;
  237. Getmem(Relocs,sizeof(RELOC)*sc.s_nreloc);
  238. seek(input_f, sc.s_relptr);
  239. Blockread (input_f,relocs^,sc.s_nreloc*RELSZ);;
  240. Close(input_f);
  241. If errors>0 Then
  242. Begin
  243. Writeln(' Errors: ',Errors);
  244. Halt(Errors);
  245. End;
  246. Assign(Output_F,argv[1]);
  247. {$I-}
  248. Rewrite(output_f,1);
  249. {$I+}
  250. If Ioresult<>0 Then
  251. Begin
  252. Writeln('can''t write file ',argv[1]);
  253. Halt(1);
  254. End;
  255. If sc.s_nreloc<>0 Then
  256. For I:=0 To sc.s_nreloc-1 Do
  257. Begin
  258. If (fixrelocs(i)^.r_type And 255)=$14 Then
  259. Dec(dh.nrelocs); { Don't do these, they are relative }
  260. End;
  261. Dosswap(@dh,'llll');
  262. Dosswap(@dh, 'llll');
  263. BlockWrite(output_f,dh,sizeof(dh));
  264. Blockwrite(output_f,data^,sc.s_size,I);
  265. If sc.s_nreloc<>0 Then
  266. For I:=0 To sc.s_nreloc-1 Do
  267. Begin
  268. If (fixrelocs(i)^.r_type And 255)<>$14 Then
  269. blockwrite(output_f,fixrelocs(i)^.r_vaddr , 4,written);
  270. End;
  271. Close(output_f);
  272. End.
  273. {
  274. $Log$
  275. Revision 1.6 2002-09-07 15:40:31 peter
  276. * old logs removed and tabs fixed
  277. Revision 1.5 2002/07/14 13:39:45 carl
  278. * use special symbols for portability's sake
  279. Revision 1.4 2002/06/01 18:39:15 marco
  280. * Renamefest
  281. }