dxegen.pp 8.0 KB

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