dxegen.pp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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,dxetype,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 FPC_BIG_ENDIAN}
  27. Var data : pbyte;
  28. c : byte;
  29. i,j : longint;
  30. {$endif FPC_BIG_ENDIAN}
  31. Begin
  32. {$ifdef FPC_BIG_ENDIAN}
  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 FPC_BIG_ENDIAN}
  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 := cardinal (-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. I := 0;
  197. while I < fh.f_nsyms do
  198. Begin
  199. If (sym[i].e.e.e_zeroes<>0) Then
  200. Begin
  201. dosswap(@sym[i], '8lscc');
  202. move(sym[i].e.e_name,tmp,8);
  203. tmp[8] := #0;
  204. name := @tmp;
  205. End
  206. Else
  207. Begin
  208. dosswap(@sym[i], 'lllscc');
  209. name := strngs + sym[i].e.e.e_offset;
  210. End;
  211. If (sym[i].e_scnum = 0) Then
  212. Begin
  213. Writeln('Error: object contains unresolved external symbols (', name,')');
  214. inc(errors);
  215. End;
  216. If (strlcomp(name, argv[2], strlen(argv[2])) = 0) Then
  217. Begin
  218. If (dh.symbol_offset <> cardinal (-1)) Then
  219. Begin
  220. Writeln('Error: multiple symbols that start with ',paramstr(2),' (',name,
  221. ')!');
  222. Inc(errors);
  223. End;
  224. dh.symbol_offset := sym[i].e_value;
  225. End
  226. Else If (strcomp(name, '.bss') = 0) And (bss_start=0) Then
  227. Begin
  228. bss_start := sym[i].e_value;
  229. Fillchar(data[bss_start], sc.s_size - bss_start,#0);
  230. End;
  231. Inc (I, Succ (sym[i].e_numaux)); (* Original C for loop iteration *)
  232. (* plus increment for found value. *)
  233. End;
  234. If (dh.symbol_offset = cardinal (-1)) Then
  235. Begin
  236. Writeln('Error: symbol ',argv[2],' not found!');
  237. Inc(Errors);
  238. End;
  239. Getmem(Relocs,sizeof(RELOC)*sc.s_nreloc);
  240. seek(input_f, sc.s_relptr);
  241. Blockread (input_f,relocs^,sc.s_nreloc*RELSZ);;
  242. Close(input_f);
  243. If errors>0 Then
  244. Begin
  245. Writeln(' Errors: ',Errors);
  246. Halt(Errors);
  247. End;
  248. Assign(Output_F,argv[1]);
  249. {$I-}
  250. Rewrite(output_f,1);
  251. {$I+}
  252. If Ioresult<>0 Then
  253. Begin
  254. Writeln('can''t write file ',argv[1]);
  255. Halt(1);
  256. End;
  257. If sc.s_nreloc<>0 Then
  258. For I:=0 To sc.s_nreloc-1 Do
  259. Begin
  260. If (fixrelocs(i)^.r_type And 255)=$14 Then
  261. Dec(dh.nrelocs); { Don't do these, they are relative }
  262. End;
  263. Dosswap(@dh,'llll');
  264. Dosswap(@dh, 'llll');
  265. BlockWrite(output_f,dh,sizeof(dh));
  266. Blockwrite(output_f,data^,sc.s_size,I);
  267. If sc.s_nreloc<>0 Then
  268. For I:=0 To sc.s_nreloc-1 Do
  269. Begin
  270. If (fixrelocs(i)^.r_type And 255)<>$14 Then
  271. blockwrite(output_f,fixrelocs(i)^.r_vaddr , 4,written);
  272. End;
  273. Close(output_f);
  274. End.
  275. {
  276. $Log$
  277. Revision 1.8 2004-09-15 19:20:51 hajny
  278. * dxegen compilable for any target now
  279. Revision 1.7 2004/09/15 08:35:39 michael
  280. + Fix for wrong for loop variable from Tomas Hajny
  281. Revision 1.6 2002/09/07 15:40:31 peter
  282. * old logs removed and tabs fixed
  283. Revision 1.5 2002/07/14 13:39:45 carl
  284. * use special symbols for portability's sake
  285. Revision 1.4 2002/06/01 18:39:15 marco
  286. * Renamefest
  287. }