dxegen.pp 8.1 KB

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