t_win32.pas 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111
  1. {
  2. $Id$
  3. Copyright (c) 1999 by Peter Vreman
  4. This unit implements support import,export,link routines
  5. for the (i386) Win32 target
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit t_win32;
  20. interface
  21. uses import,export,link;
  22. const
  23. winstackpagesize = 4096;
  24. type
  25. pimportlibwin32=^timportlibwin32;
  26. timportlibwin32=object(timportlib)
  27. procedure preparelib(const s:string);virtual;
  28. procedure importprocedure(const func,module:string;index:longint;const name:string);virtual;
  29. procedure importvariable(const varname,module:string;const name:string);virtual;
  30. procedure generatelib;virtual;
  31. procedure generatesmartlib;virtual;
  32. end;
  33. pexportlibwin32=^texportlibwin32;
  34. texportlibwin32=object(texportlib)
  35. st : string;
  36. last_index : longint;
  37. procedure preparelib(const s:string);virtual;
  38. procedure exportprocedure(hp : pexported_item);virtual;
  39. procedure exportvar(hp : pexported_item);virtual;
  40. procedure generatelib;virtual;
  41. end;
  42. plinkerwin32=^tlinkerwin32;
  43. tlinkerwin32=object(tlinker)
  44. private
  45. Function WriteResponseFile(isdll:boolean) : Boolean;
  46. Function PostProcessExecutable(const fn:string;isdll:boolean) : Boolean;
  47. public
  48. Constructor Init;
  49. Procedure SetDefaultInfo;virtual;
  50. function MakeExecutable:boolean;virtual;
  51. function MakeSharedLibrary:boolean;virtual;
  52. end;
  53. implementation
  54. uses
  55. aasm,files,globtype,globals,cobjects,systems,verbose,
  56. script,gendef,
  57. cpubase,cpuasm
  58. {$ifdef GDB}
  59. ,gdb
  60. {$endif}
  61. ;
  62. function DllName(Const Name : string) : string;
  63. var n : string;
  64. begin
  65. n:=Upper(SplitExtension(Name));
  66. if (n='.DLL') or (n='.DRV') or (n='.EXE') then
  67. DllName:=Name
  68. else
  69. DllName:=Name+target_os.sharedlibext;
  70. end;
  71. {*****************************************************************************
  72. TIMPORTLIBWIN32
  73. *****************************************************************************}
  74. procedure timportlibwin32.preparelib(const s : string);
  75. begin
  76. if not(assigned(importssection)) then
  77. importssection:=new(paasmoutput,init);
  78. end;
  79. procedure timportlibwin32.importprocedure(const func,module : string;index : longint;const name : string);
  80. var
  81. hp1 : pimportlist;
  82. hp2 : pimported_item;
  83. hs : string;
  84. begin
  85. hs:=DllName(module);
  86. { search for the module }
  87. hp1:=pimportlist(current_module^.imports^.first);
  88. while assigned(hp1) do
  89. begin
  90. if hs=hp1^.dllname^ then
  91. break;
  92. hp1:=pimportlist(hp1^.next);
  93. end;
  94. { generate a new item ? }
  95. if not(assigned(hp1)) then
  96. begin
  97. hp1:=new(pimportlist,init(hs));
  98. current_module^.imports^.concat(hp1);
  99. end;
  100. { search for reuse of old import item }
  101. hp2:=pimported_item(hp1^.imported_items^.first);
  102. while assigned(hp2) do
  103. begin
  104. if hp2^.func^=func then
  105. break;
  106. hp2:=pimported_item(hp2^.next);
  107. end;
  108. if not assigned(hp2) then
  109. begin
  110. hp2:=new(pimported_item,init(func,name,index));
  111. hp1^.imported_items^.concat(hp2);
  112. end;
  113. end;
  114. procedure timportlibwin32.importvariable(const varname,module:string;const name:string);
  115. var
  116. hp1 : pimportlist;
  117. hp2 : pimported_item;
  118. hs : string;
  119. begin
  120. hs:=DllName(module);
  121. { search for the module }
  122. hp1:=pimportlist(current_module^.imports^.first);
  123. while assigned(hp1) do
  124. begin
  125. if hs=hp1^.dllname^ then
  126. break;
  127. hp1:=pimportlist(hp1^.next);
  128. end;
  129. { generate a new item ? }
  130. if not(assigned(hp1)) then
  131. begin
  132. hp1:=new(pimportlist,init(hs));
  133. current_module^.imports^.concat(hp1);
  134. end;
  135. hp2:=new(pimported_item,init_var(varname,name));
  136. hp1^.imported_items^.concat(hp2);
  137. end;
  138. procedure timportlibwin32.generatesmartlib;
  139. var
  140. hp1 : pimportlist;
  141. hp2 : pimported_item;
  142. lhead,lname,lcode,
  143. lidata4,lidata5 : pasmlabel;
  144. r : preference;
  145. begin
  146. hp1:=pimportlist(current_module^.imports^.first);
  147. while assigned(hp1) do
  148. begin
  149. { Get labels for the sections }
  150. getdatalabel(lhead);
  151. getdatalabel(lname);
  152. getlabel(lidata4);
  153. getlabel(lidata5);
  154. { create header for this importmodule }
  155. importssection^.concat(new(pai_cut,init_begin));
  156. importssection^.concat(new(pai_section,init(sec_idata2)));
  157. importssection^.concat(new(pai_label,init(lhead)));
  158. { pointer to procedure names }
  159. importssection^.concat(new(pai_const_symbol,init_rva(lidata4)));
  160. { two empty entries follow }
  161. importssection^.concat(new(pai_const,init_32bit(0)));
  162. importssection^.concat(new(pai_const,init_32bit(0)));
  163. { pointer to dll name }
  164. importssection^.concat(new(pai_const_symbol,init_rva(lname)));
  165. { pointer to fixups }
  166. importssection^.concat(new(pai_const_symbol,init_rva(lidata5)));
  167. { first write the name references }
  168. importssection^.concat(new(pai_section,init(sec_idata4)));
  169. importssection^.concat(new(pai_const,init_32bit(0)));
  170. importssection^.concat(new(pai_label,init(lidata4)));
  171. { then the addresses and create also the indirect jump }
  172. importssection^.concat(new(pai_section,init(sec_idata5)));
  173. importssection^.concat(new(pai_const,init_32bit(0)));
  174. importssection^.concat(new(pai_label,init(lidata5)));
  175. { create procedures }
  176. hp2:=pimported_item(hp1^.imported_items^.first);
  177. while assigned(hp2) do
  178. begin
  179. { insert cuts }
  180. importssection^.concat(new(pai_cut,init));
  181. { create indirect jump }
  182. if not hp2^.is_var then
  183. begin
  184. getlabel(lcode);
  185. new(r);
  186. reset_reference(r^);
  187. r^.symbol:=lcode;
  188. { place jump in codesegment, insert a code section in the
  189. importsection to reduce the amount of .s files (PFV) }
  190. importssection^.concat(new(pai_section,init(sec_code)));
  191. {$IfDef GDB}
  192. if (cs_debuginfo in aktmoduleswitches) then
  193. importssection^.concat(new(pai_stab_function_name,init(nil)));
  194. {$EndIf GDB}
  195. importssection^.concat(new(pai_symbol,initname_global(hp2^.func^,0)));
  196. importssection^.concat(new(paicpu,op_ref(A_JMP,S_NO,r)));
  197. importssection^.concat(new(pai_align,init_op(4,$90)));
  198. end;
  199. { create head link }
  200. importssection^.concat(new(pai_section,init(sec_idata7)));
  201. importssection^.concat(new(pai_const_symbol,init_rva(lhead)));
  202. { fixup }
  203. getlabel(pasmlabel(hp2^.lab));
  204. importssection^.concat(new(pai_section,init(sec_idata4)));
  205. importssection^.concat(new(pai_const_symbol,init_rva(hp2^.lab)));
  206. { add jump field to importsection }
  207. importssection^.concat(new(pai_section,init(sec_idata5)));
  208. if hp2^.is_var then
  209. importssection^.concat(new(pai_symbol,initname_global(hp2^.func^,0)))
  210. else
  211. importssection^.concat(new(pai_label,init(lcode)));
  212. if hp2^.name^<>'' then
  213. importssection^.concat(new(pai_const_symbol,init_rva(hp2^.lab)))
  214. else
  215. importssection^.concat(new(pai_const,init_32bit($80000000 or hp2^.ordnr)));
  216. { finally the import information }
  217. importssection^.concat(new(pai_section,init(sec_idata6)));
  218. importssection^.concat(new(pai_label,init(hp2^.lab)));
  219. importssection^.concat(new(pai_const,init_16bit(hp2^.ordnr)));
  220. importssection^.concat(new(pai_string,init(hp2^.name^+#0)));
  221. importssection^.concat(new(pai_align,init_op(2,0)));
  222. hp2:=pimported_item(hp2^.next);
  223. end;
  224. { write final section }
  225. importssection^.concat(new(pai_cut,init_end));
  226. { end of name references }
  227. importssection^.concat(new(pai_section,init(sec_idata4)));
  228. importssection^.concat(new(pai_const,init_32bit(0)));
  229. { end if addresses }
  230. importssection^.concat(new(pai_section,init(sec_idata5)));
  231. importssection^.concat(new(pai_const,init_32bit(0)));
  232. { dllname }
  233. importssection^.concat(new(pai_section,init(sec_idata7)));
  234. importssection^.concat(new(pai_label,init(lname)));
  235. importssection^.concat(new(pai_string,init(hp1^.dllname^+#0)));
  236. hp1:=pimportlist(hp1^.next);
  237. end;
  238. end;
  239. procedure timportlibwin32.generatelib;
  240. var
  241. hp1 : pimportlist;
  242. hp2 : pimported_item;
  243. l1,l2,l3,l4 : pasmlabel;
  244. r : preference;
  245. begin
  246. hp1:=pimportlist(current_module^.imports^.first);
  247. while assigned(hp1) do
  248. begin
  249. { align codesegment for the jumps }
  250. importssection^.concat(new(pai_section,init(sec_code)));
  251. importssection^.concat(new(pai_align,init_op(4,$90)));
  252. { Get labels for the sections }
  253. getlabel(l1);
  254. getlabel(l2);
  255. getlabel(l3);
  256. importssection^.concat(new(pai_section,init(sec_idata2)));
  257. { pointer to procedure names }
  258. importssection^.concat(new(pai_const_symbol,init_rva(l2)));
  259. { two empty entries follow }
  260. importssection^.concat(new(pai_const,init_32bit(0)));
  261. importssection^.concat(new(pai_const,init_32bit(0)));
  262. { pointer to dll name }
  263. importssection^.concat(new(pai_const_symbol,init_rva(l1)));
  264. { pointer to fixups }
  265. importssection^.concat(new(pai_const_symbol,init_rva(l3)));
  266. { only create one section for each else it will
  267. create a lot of idata* }
  268. { first write the name references }
  269. importssection^.concat(new(pai_section,init(sec_idata4)));
  270. importssection^.concat(new(pai_label,init(l2)));
  271. hp2:=pimported_item(hp1^.imported_items^.first);
  272. while assigned(hp2) do
  273. begin
  274. getlabel(pasmlabel(hp2^.lab));
  275. if hp2^.name^<>'' then
  276. importssection^.concat(new(pai_const_symbol,init_rva(hp2^.lab)))
  277. else
  278. importssection^.concat(new(pai_const,init_32bit($80000000 or hp2^.ordnr)));
  279. hp2:=pimported_item(hp2^.next);
  280. end;
  281. { finalize the names ... }
  282. importssection^.concat(new(pai_const,init_32bit(0)));
  283. { then the addresses and create also the indirect jump }
  284. importssection^.concat(new(pai_section,init(sec_idata5)));
  285. importssection^.concat(new(pai_label,init(l3)));
  286. hp2:=pimported_item(hp1^.imported_items^.first);
  287. while assigned(hp2) do
  288. begin
  289. if not hp2^.is_var then
  290. begin
  291. getlabel(l4);
  292. { create indirect jump }
  293. new(r);
  294. reset_reference(r^);
  295. r^.symbol:=l4;
  296. { place jump in codesegment }
  297. importssection^.concat(new(pai_section,init(sec_code)));
  298. importssection^.concat(new(pai_symbol,initname_global(hp2^.func^,0)));
  299. importssection^.concat(new(paicpu,op_ref(A_JMP,S_NO,r)));
  300. importssection^.concat(new(pai_align,init_op(4,$90)));
  301. { add jump field to importsection }
  302. importssection^.concat(new(pai_section,init(sec_idata5)));
  303. importssection^.concat(new(pai_label,init(l4)));
  304. end
  305. else
  306. begin
  307. importssection^.concat(new(pai_symbol,initname_global(hp2^.func^,0)));
  308. end;
  309. importssection^.concat(new(pai_const_symbol,init_rva(hp2^.lab)));
  310. hp2:=pimported_item(hp2^.next);
  311. end;
  312. { finalize the addresses }
  313. importssection^.concat(new(pai_const,init_32bit(0)));
  314. { finally the import information }
  315. importssection^.concat(new(pai_section,init(sec_idata6)));
  316. hp2:=pimported_item(hp1^.imported_items^.first);
  317. while assigned(hp2) do
  318. begin
  319. importssection^.concat(new(pai_label,init(hp2^.lab)));
  320. { the ordinal number }
  321. importssection^.concat(new(pai_const,init_16bit(hp2^.ordnr)));
  322. importssection^.concat(new(pai_string,init(hp2^.name^+#0)));
  323. importssection^.concat(new(pai_align,init_op(2,0)));
  324. hp2:=pimported_item(hp2^.next);
  325. end;
  326. { create import dll name }
  327. importssection^.concat(new(pai_section,init(sec_idata7)));
  328. importssection^.concat(new(pai_label,init(l1)));
  329. importssection^.concat(new(pai_string,init(hp1^.dllname^+#0)));
  330. hp1:=pimportlist(hp1^.next);
  331. end;
  332. end;
  333. {*****************************************************************************
  334. TEXPORTLIBWIN32
  335. *****************************************************************************}
  336. procedure texportlibwin32.preparelib(const s:string);
  337. begin
  338. if not(assigned(exportssection)) then
  339. exportssection:=new(paasmoutput,init);
  340. last_index:=0;
  341. end;
  342. procedure texportlibwin32.exportvar(hp : pexported_item);
  343. begin
  344. { same code used !! PM }
  345. exportprocedure(hp);
  346. end;
  347. procedure texportlibwin32.exportprocedure(hp : pexported_item);
  348. { must be ordered at least for win32 !! }
  349. var
  350. hp2 : pexported_item;
  351. begin
  352. { first test the index value }
  353. if (hp^.options and eo_index)<>0 then
  354. begin
  355. if (hp^.index<=0) or (hp^.index>$ffff) then
  356. begin
  357. message1(parser_e_export_invalid_index,tostr(hp^.index));
  358. exit;
  359. end;
  360. if (hp^.index<=last_index) then
  361. begin
  362. message1(parser_e_export_ordinal_double,tostr(hp^.index));
  363. { disregard index value }
  364. inc(last_index);
  365. hp^.index:=last_index;
  366. exit;
  367. end
  368. else
  369. begin
  370. last_index:=hp^.index;
  371. end;
  372. end
  373. else
  374. begin
  375. inc(last_index);
  376. hp^.index:=last_index;
  377. end;
  378. { use pascal name is none specified }
  379. if (hp^.options and eo_name)=0 then
  380. begin
  381. hp^.name:=stringdup(hp^.sym^.name);
  382. hp^.options:=hp^.options or eo_name;
  383. end;
  384. { now place in correct order }
  385. hp2:=pexported_item(current_module^._exports^.first);
  386. while assigned(hp2) and
  387. (hp^.name^>hp2^.name^) do
  388. hp2:=pexported_item(hp2^.next);
  389. { insert hp there !! }
  390. if assigned(hp2) and (hp2^.name^=hp^.name^) then
  391. begin
  392. { this is not allowed !! }
  393. message1(parser_e_export_name_double,hp^.name^);
  394. exit;
  395. end;
  396. if hp2=pexported_item(current_module^._exports^.first) then
  397. current_module^._exports^.insert(hp)
  398. else if assigned(hp2) then
  399. begin
  400. hp^.next:=hp2;
  401. hp^.previous:=hp2^.previous;
  402. if assigned(hp2^.previous) then
  403. hp2^.previous^.next:=hp;
  404. hp2^.previous:=hp;
  405. end
  406. else
  407. current_module^._exports^.concat(hp);
  408. end;
  409. procedure texportlibwin32.generatelib;
  410. var
  411. ordinal_base,ordinal_max,ordinal_min : longint;
  412. current_index : longint;
  413. entries,named_entries : longint;
  414. name_label,dll_name_label,export_address_table : pasmlabel;
  415. export_name_table_pointers,export_ordinal_table : pasmlabel;
  416. hp,hp2 : pexported_item;
  417. tempexport : plinkedlist;
  418. address_table,name_table_pointers,
  419. name_table,ordinal_table : paasmoutput;
  420. begin
  421. ordinal_max:=0;
  422. ordinal_min:=$7FFFFFFF;
  423. entries:=0;
  424. named_entries:=0;
  425. getlabel(dll_name_label);
  426. getlabel(export_address_table);
  427. getlabel(export_name_table_pointers);
  428. getlabel(export_ordinal_table);
  429. hp:=pexported_item(current_module^._exports^.first);
  430. { count entries }
  431. while assigned(hp) do
  432. begin
  433. inc(entries);
  434. if (hp^.index>ordinal_max) then
  435. ordinal_max:=hp^.index;
  436. if (hp^.index>0) and (hp^.index<ordinal_min) then
  437. ordinal_min:=hp^.index;
  438. if assigned(hp^.name) then
  439. inc(named_entries);
  440. hp:=pexported_item(hp^.next);
  441. end;
  442. { no support for higher ordinal base yet !! }
  443. ordinal_base:=1;
  444. current_index:=ordinal_base;
  445. { we must also count the holes !! }
  446. entries:=ordinal_max-ordinal_base+1;
  447. exportssection^.concat(new(pai_section,init(sec_edata)));
  448. { export flags }
  449. exportssection^.concat(new(pai_const,init_32bit(0)));
  450. { date/time stamp }
  451. exportssection^.concat(new(pai_const,init_32bit(0)));
  452. { major version }
  453. exportssection^.concat(new(pai_const,init_16bit(0)));
  454. { minor version }
  455. exportssection^.concat(new(pai_const,init_16bit(0)));
  456. { pointer to dll name }
  457. exportssection^.concat(new(pai_const_symbol,init_rva(dll_name_label)));
  458. { ordinal base normally set to 1 }
  459. exportssection^.concat(new(pai_const,init_32bit(ordinal_base)));
  460. { number of entries }
  461. exportssection^.concat(new(pai_const,init_32bit(entries)));
  462. { number of named entries }
  463. exportssection^.concat(new(pai_const,init_32bit(named_entries)));
  464. { address of export address table }
  465. exportssection^.concat(new(pai_const_symbol,init_rva(export_address_table)));
  466. { address of name pointer pointers }
  467. exportssection^.concat(new(pai_const_symbol,init_rva(export_name_table_pointers)));
  468. { address of ordinal number pointers }
  469. exportssection^.concat(new(pai_const_symbol,init_rva(export_ordinal_table)));
  470. { the name }
  471. exportssection^.concat(new(pai_label,init(dll_name_label)));
  472. if st='' then
  473. exportssection^.concat(new(pai_string,init(current_module^.modulename^+target_os.sharedlibext+#0)))
  474. else
  475. exportssection^.concat(new(pai_string,init(st+target_os.sharedlibext+#0)));
  476. { export address table }
  477. address_table:=new(paasmoutput,init);
  478. address_table^.concat(new(pai_align,init_op(4,0)));
  479. address_table^.concat(new(pai_label,init(export_address_table)));
  480. name_table_pointers:=new(paasmoutput,init);
  481. name_table_pointers^.concat(new(pai_align,init_op(4,0)));
  482. name_table_pointers^.concat(new(pai_label,init(export_name_table_pointers)));
  483. ordinal_table:=new(paasmoutput,init);
  484. ordinal_table^.concat(new(pai_align,init_op(4,0)));
  485. ordinal_table^.concat(new(pai_label,init(export_ordinal_table)));
  486. name_table:=new(paasmoutput,init);
  487. name_table^.concat(new(pai_align,init_op(4,0)));
  488. { write each address }
  489. hp:=pexported_item(current_module^._exports^.first);
  490. while assigned(hp) do
  491. begin
  492. if (hp^.options and eo_name)<>0 then
  493. begin
  494. getlabel(name_label);
  495. name_table_pointers^.concat(new(pai_const_symbol,init_rva(name_label)));
  496. ordinal_table^.concat(new(pai_const,init_16bit(hp^.index-ordinal_base)));
  497. name_table^.concat(new(pai_align,init_op(2,0)));
  498. name_table^.concat(new(pai_label,init(name_label)));
  499. name_table^.concat(new(pai_string,init(hp^.name^+#0)));
  500. end;
  501. hp:=pexported_item(hp^.next);
  502. end;
  503. { order in increasing ordinal values }
  504. { into tempexport list }
  505. tempexport:=new(plinkedlist,init);
  506. hp:=pexported_item(current_module^._exports^.first);
  507. while assigned(hp) do
  508. begin
  509. current_module^._exports^.remove(hp);
  510. hp2:=pexported_item(tempexport^.first);
  511. while assigned(hp2) and (hp^.index>hp2^.index) do
  512. begin
  513. hp2:=pexported_item(hp2^.next);
  514. end;
  515. if hp2=pexported_item(tempexport^.first) then
  516. tempexport^.insert(hp)
  517. else
  518. begin
  519. if assigned(hp2) then
  520. begin
  521. hp^.next:=hp2;
  522. hp^.previous:=hp2^.previous;
  523. hp2^.previous:=hp;
  524. if assigned(hp^.previous) then
  525. hp^.previous^.next:=hp;
  526. end
  527. else
  528. tempexport^.concat(hp);
  529. end;
  530. hp:=pexported_item(current_module^._exports^.first);;
  531. end;
  532. { write the export adress table }
  533. current_index:=ordinal_base;
  534. hp:=pexported_item(tempexport^.first);
  535. while assigned(hp) do
  536. begin
  537. { fill missing values }
  538. while current_index<hp^.index do
  539. begin
  540. address_table^.concat(new(pai_const,init_32bit(0)));
  541. inc(current_index);
  542. end;
  543. address_table^.concat(new(pai_const_symbol,initname_rva(hp^.sym^.mangledname)));
  544. inc(current_index);
  545. hp:=pexported_item(hp^.next);
  546. end;
  547. exportssection^.concatlist(address_table);
  548. exportssection^.concatlist(name_table_pointers);
  549. exportssection^.concatlist(ordinal_table);
  550. exportssection^.concatlist(name_table);
  551. dispose(address_table,done);
  552. dispose(name_table_pointers,done);
  553. dispose(ordinal_table,done);
  554. dispose(name_table,done);
  555. dispose(tempexport,done);
  556. end;
  557. {****************************************************************************
  558. TLINKERWIN32
  559. ****************************************************************************}
  560. Constructor TLinkerWin32.Init;
  561. begin
  562. Inherited Init;
  563. { allow duplicated libs (PM) }
  564. SharedLibFiles.doubles:=true;
  565. StaticLibFiles.doubles:=true;
  566. If not ForceDeffileForExport then
  567. UseDeffileForExport:=false;
  568. end;
  569. Procedure TLinkerWin32.SetDefaultInfo;
  570. begin
  571. with Info do
  572. begin
  573. ExeCmd[1]:='ldw $OPT $STRIP $APPTYPE $IMAGEBASE $RELOC -o $EXE $RES';
  574. DllCmd[1]:='ldw $OPT $STRIP --dll $APPTYPE $IMAGEBASE $RELOC -o $EXE $RES';
  575. if UseDeffileForExport then
  576. begin
  577. ExeCmd[2]:='dlltool --as $ASBIN --dllname $EXE --output-exp exp.$$$ $RELOC $DEF';
  578. ExeCmd[3]:='ldw $OPT $STRIP $APPTYPE $IMAGEBASE -o $EXE $RES exp.$$$';
  579. DllCmd[2]:='dlltool --as $ASBIN --dllname $EXE --output-exp exp.$$$ $RELOC $DEF';
  580. DllCmd[3]:='ldw $OPT $STRIP --dll $APPTYPE $IMAGEBASE -o $EXE $RES exp.$$$';
  581. end;
  582. end;
  583. end;
  584. Function TLinkerWin32.WriteResponseFile(isdll:boolean) : Boolean;
  585. Var
  586. linkres : TLinkRes;
  587. i : longint;
  588. HPath : PStringQueueItem;
  589. s : string;
  590. linklibc : boolean;
  591. begin
  592. WriteResponseFile:=False;
  593. { Open link.res file }
  594. LinkRes.Init(outputexedir+Info.ResName);
  595. { Write path to search libraries }
  596. HPath:=current_module^.locallibrarysearchpath.First;
  597. while assigned(HPath) do
  598. begin
  599. LinkRes.Add('SEARCH_DIR('+GetShortName(HPath^.Data^)+')');
  600. HPath:=HPath^.Next;
  601. end;
  602. HPath:=LibrarySearchPath.First;
  603. while assigned(HPath) do
  604. begin
  605. LinkRes.Add('SEARCH_DIR('+GetShortName(HPath^.Data^)+')');
  606. HPath:=HPath^.Next;
  607. end;
  608. { add objectfiles, start with prt0 always }
  609. LinkRes.Add('INPUT(');
  610. if isdll then
  611. LinkRes.AddFileName(GetShortName(FindObjectFile('wdllprt0')))
  612. else
  613. LinkRes.AddFileName(GetShortName(FindObjectFile('wprt0')));
  614. while not ObjectFiles.Empty do
  615. begin
  616. s:=ObjectFiles.Get;
  617. if s<>'' then
  618. LinkRes.AddFileName(GetShortName(s));
  619. end;
  620. { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
  621. here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
  622. linklibc:=false;
  623. While not SharedLibFiles.Empty do
  624. begin
  625. S:=SharedLibFiles.Get;
  626. if s<>'c' then
  627. begin
  628. i:=Pos(target_os.sharedlibext,S);
  629. if i>0 then
  630. Delete(S,i,255);
  631. LinkRes.Add('-l'+s);
  632. end
  633. else
  634. begin
  635. LinkRes.Add('-l'+s);
  636. linklibc:=true;
  637. end;
  638. end;
  639. { be sure that libc is the last lib }
  640. if linklibc then
  641. LinkRes.Add('-lc');
  642. LinkRes.Add(')');
  643. { Write staticlibraries }
  644. if not StaticLibFiles.Empty then
  645. begin
  646. LinkRes.Add('GROUP(');
  647. While not StaticLibFiles.Empty do
  648. begin
  649. S:=StaticLibFiles.Get;
  650. LinkRes.AddFileName(GetShortName(s));
  651. end;
  652. LinkRes.Add(')');
  653. end;
  654. { Write and Close response }
  655. linkres.writetodisk;
  656. linkres.done;
  657. WriteResponseFile:=True;
  658. end;
  659. function TLinkerWin32.MakeExecutable:boolean;
  660. var
  661. binstr,
  662. cmdstr : string;
  663. found,
  664. success : boolean;
  665. i : longint;
  666. AsBinStr : string[80];
  667. StripStr,
  668. RelocStr,
  669. AppTypeStr,
  670. ImageBaseStr : string[40];
  671. begin
  672. if not(cs_link_extern in aktglobalswitches) then
  673. Message1(exec_i_linking,current_module^.exefilename^);
  674. { Create some replacements }
  675. RelocStr:='';
  676. AppTypeStr:='';
  677. ImageBaseStr:='';
  678. StripStr:='';
  679. AsBinStr:=FindExe('asw',found);
  680. if UseDeffileForExport then
  681. RelocStr:='--base-file base.$$$';
  682. if apptype=at_gui then
  683. AppTypeStr:='--subsystem windows';
  684. if assigned(DLLImageBase) then
  685. ImageBaseStr:='--image-base=0x'+DLLImageBase^;
  686. if (cs_link_strip in aktglobalswitches) then
  687. StripStr:='-s';
  688. { Write used files and libraries }
  689. WriteResponseFile(false);
  690. { Call linker }
  691. success:=false;
  692. for i:=1 to 3 do
  693. begin
  694. SplitBinCmd(Info.ExeCmd[i],binstr,cmdstr);
  695. if binstr<>'' then
  696. begin
  697. Replace(cmdstr,'$EXE',current_module^.exefilename^);
  698. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  699. Replace(cmdstr,'$RES',outputexedir+Info.ResName);
  700. Replace(cmdstr,'$APPTYPE',AppTypeStr);
  701. Replace(cmdstr,'$ASBIN',AsbinStr);
  702. Replace(cmdstr,'$RELOC',RelocStr);
  703. Replace(cmdstr,'$IMAGEBASE',ImageBaseStr);
  704. Replace(cmdstr,'$STRIP',StripStr);
  705. if not DefFile.Empty then
  706. Replace(cmdstr,'$DEF','-d '+deffile.fname)
  707. else
  708. Replace(cmdstr,'$DEF','');
  709. success:=DoExec(FindUtil(binstr),cmdstr,(i=1),false);
  710. if not success then
  711. break;
  712. end;
  713. end;
  714. { Post process }
  715. if success then
  716. success:=PostProcessExecutable(current_module^.exefilename^,false);
  717. { Remove ReponseFile }
  718. if (success) and not(cs_link_extern in aktglobalswitches) then
  719. begin
  720. RemoveFile(outputexedir+Info.ResName);
  721. RemoveFile('base.$$$');
  722. RemoveFile('exp.$$$');
  723. end;
  724. MakeExecutable:=success; { otherwise a recursive call to link method }
  725. end;
  726. Function TLinkerWin32.MakeSharedLibrary:boolean;
  727. var
  728. binstr,
  729. cmdstr : string;
  730. found,
  731. success : boolean;
  732. i : longint;
  733. AsBinStr : string[80];
  734. StripStr,
  735. RelocStr,
  736. AppTypeStr,
  737. ImageBaseStr : string[40];
  738. begin
  739. MakeSharedLibrary:=false;
  740. if not(cs_link_extern in aktglobalswitches) then
  741. Message1(exec_i_linking,current_module^.sharedlibfilename^);
  742. { Create some replacements }
  743. RelocStr:='';
  744. AppTypeStr:='';
  745. ImageBaseStr:='';
  746. StripStr:='';
  747. AsBinStr:=FindExe('asw',found);
  748. if UseDeffileForExport then
  749. RelocStr:='--base-file base.$$$';
  750. if apptype=at_gui then
  751. AppTypeStr:='--subsystem windows';
  752. if assigned(DLLImageBase) then
  753. ImageBaseStr:='--image-base=0x'+DLLImageBase^;
  754. if (cs_link_strip in aktglobalswitches) then
  755. StripStr:='-s';
  756. { Write used files and libraries }
  757. WriteResponseFile(true);
  758. { Call linker }
  759. success:=false;
  760. for i:=1to 3 do
  761. begin
  762. SplitBinCmd(Info.DllCmd[i],binstr,cmdstr);
  763. if binstr<>'' then
  764. begin
  765. Replace(cmdstr,'$EXE',current_module^.sharedlibfilename^);
  766. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  767. Replace(cmdstr,'$RES',outputexedir+Info.ResName);
  768. Replace(cmdstr,'$APPTYPE',AppTypeStr);
  769. Replace(cmdstr,'$ASBIN',AsbinStr);
  770. Replace(cmdstr,'$RELOC',RelocStr);
  771. Replace(cmdstr,'$IMAGEBASE',ImageBaseStr);
  772. Replace(cmdstr,'$STRIP',StripStr);
  773. if not DefFile.Empty then
  774. Replace(cmdstr,'$DEF','-d '+deffile.fname)
  775. else
  776. Replace(cmdstr,'$DEF','');
  777. success:=DoExec(FindUtil(binstr),cmdstr,(i=1),false);
  778. if not success then
  779. break;
  780. end;
  781. end;
  782. { Post process }
  783. if success then
  784. success:=PostProcessExecutable(current_module^.sharedlibfilename^,true);
  785. { Remove ReponseFile }
  786. if (success) and not(cs_link_extern in aktglobalswitches) then
  787. begin
  788. RemoveFile(outputexedir+Info.ResName);
  789. RemoveFile('base.$$$');
  790. RemoveFile('exp.$$$');
  791. end;
  792. MakeSharedLibrary:=success; { otherwise a recursive call to link method }
  793. end;
  794. function tlinkerwin32.postprocessexecutable(const fn : string;isdll:boolean):boolean;
  795. type
  796. tdosheader = packed record
  797. e_magic : word;
  798. e_cblp : word;
  799. e_cp : word;
  800. e_crlc : word;
  801. e_cparhdr : word;
  802. e_minalloc : word;
  803. e_maxalloc : word;
  804. e_ss : word;
  805. e_sp : word;
  806. e_csum : word;
  807. e_ip : word;
  808. e_cs : word;
  809. e_lfarlc : word;
  810. e_ovno : word;
  811. e_res : array[0..3] of word;
  812. e_oemid : word;
  813. e_oeminfo : word;
  814. e_res2 : array[0..9] of word;
  815. e_lfanew : longint;
  816. end;
  817. tpeheader = packed record
  818. PEMagic : array[0..3] of char;
  819. Machine : word;
  820. NumberOfSections : word;
  821. TimeDateStamp : longint;
  822. PointerToSymbolTable : longint;
  823. NumberOfSymbols : longint;
  824. SizeOfOptionalHeader : word;
  825. Characteristics : word;
  826. Magic : word;
  827. MajorLinkerVersion : byte;
  828. MinorLinkerVersion : byte;
  829. SizeOfCode : longint;
  830. SizeOfInitializedData : longint;
  831. SizeOfUninitializedData : longint;
  832. AddressOfEntryPoint : longint;
  833. BaseOfCode : longint;
  834. BaseOfData : longint;
  835. ImageBase : longint;
  836. SectionAlignment : longint;
  837. FileAlignment : longint;
  838. MajorOperatingSystemVersion : word;
  839. MinorOperatingSystemVersion : word;
  840. MajorImageVersion : word;
  841. MinorImageVersion : word;
  842. MajorSubsystemVersion : word;
  843. MinorSubsystemVersion : word;
  844. Reserved1 : longint;
  845. SizeOfImage : longint;
  846. SizeOfHeaders : longint;
  847. CheckSum : longint;
  848. Subsystem : word;
  849. DllCharacteristics : word;
  850. SizeOfStackReserve : longint;
  851. SizeOfStackCommit : longint;
  852. SizeOfHeapReserve : longint;
  853. SizeOfHeapCommit : longint;
  854. LoaderFlags : longint;
  855. NumberOfRvaAndSizes : longint;
  856. DataDirectory : array[1..$80] of byte;
  857. end;
  858. tcoffsechdr=packed record
  859. name : array[0..7] of char;
  860. vsize : longint;
  861. rvaofs : longint;
  862. datalen : longint;
  863. datapos : longint;
  864. relocpos : longint;
  865. lineno1 : longint;
  866. nrelocs : word;
  867. lineno2 : word;
  868. flags : longint;
  869. end;
  870. psecfill=^tsecfill;
  871. tsecfill=record
  872. fillpos,
  873. fillsize : longint;
  874. next : psecfill;
  875. end;
  876. var
  877. f : file;
  878. dosheader : tdosheader;
  879. peheader : tpeheader;
  880. firstsecpos,
  881. maxfillsize,
  882. i,l,peheaderpos : longint;
  883. coffsec : tcoffsechdr;
  884. secroot,hsecroot : psecfill;
  885. zerobuf : pointer;
  886. begin
  887. postprocessexecutable:=false;
  888. { when -s is used or it's a dll then quit }
  889. if (cs_link_extern in aktglobalswitches) then
  890. begin
  891. postprocessexecutable:=true;
  892. exit;
  893. end;
  894. { open file }
  895. assign(f,fn);
  896. {$I-}
  897. reset(f,1);
  898. if ioresult<>0 then
  899. Message1(execinfo_f_cant_open_executable,fn);
  900. { read headers }
  901. blockread(f,dosheader,sizeof(tdosheader));
  902. peheaderpos:=dosheader.e_lfanew;
  903. seek(f,peheaderpos);
  904. blockread(f,peheader,sizeof(tpeheader));
  905. { write info }
  906. Message1(execinfo_x_codesize,tostr(peheader.SizeOfCode));
  907. Message1(execinfo_x_initdatasize,tostr(peheader.SizeOfInitializedData));
  908. Message1(execinfo_x_uninitdatasize,tostr(peheader.SizeOfUninitializedData));
  909. { change stack size (PM) }
  910. { I am not sure that the default value is adequate !! }
  911. peheader.SizeOfStackReserve:=stacksize;
  912. { change the header }
  913. { sub system }
  914. { gui=2 }
  915. { cui=3 }
  916. if apptype=at_gui then
  917. peheader.Subsystem:=2
  918. else if apptype=at_cui then
  919. peheader.Subsystem:=3;
  920. seek(f,peheaderpos);
  921. blockwrite(f,peheader,sizeof(tpeheader));
  922. if ioresult<>0 then
  923. Message1(execinfo_f_cant_process_executable,fn);
  924. seek(f,peheaderpos);
  925. blockread(f,peheader,sizeof(tpeheader));
  926. { write the value after the change }
  927. Message1(execinfo_x_stackreserve,tostr(peheader.SizeOfStackReserve));
  928. Message1(execinfo_x_stackcommit,tostr(peheader.SizeOfStackCommit));
  929. { read section info }
  930. maxfillsize:=0;
  931. firstsecpos:=0;
  932. secroot:=nil;
  933. for l:=1to peheader.NumberOfSections do
  934. begin
  935. blockread(f,coffsec,sizeof(tcoffsechdr));
  936. if coffsec.datapos>0 then
  937. begin
  938. if secroot=nil then
  939. firstsecpos:=coffsec.datapos;
  940. new(hsecroot);
  941. hsecroot^.fillpos:=coffsec.datapos+coffsec.vsize;
  942. hsecroot^.fillsize:=coffsec.datalen-coffsec.vsize;
  943. hsecroot^.next:=secroot;
  944. secroot:=hsecroot;
  945. if secroot^.fillsize>maxfillsize then
  946. maxfillsize:=secroot^.fillsize;
  947. end;
  948. end;
  949. if firstsecpos>0 then
  950. begin
  951. l:=firstsecpos-filepos(f);
  952. if l>maxfillsize then
  953. maxfillsize:=l;
  954. end
  955. else
  956. l:=0;
  957. { get zero buffer }
  958. getmem(zerobuf,maxfillsize);
  959. fillchar(zerobuf^,maxfillsize,0);
  960. { zero from sectioninfo until first section }
  961. blockwrite(f,zerobuf^,l);
  962. { zero section alignments }
  963. while assigned(secroot) do
  964. begin
  965. seek(f,secroot^.fillpos);
  966. blockwrite(f,zerobuf^,secroot^.fillsize);
  967. hsecroot:=secroot;
  968. secroot:=secroot^.next;
  969. dispose(hsecroot);
  970. end;
  971. freemem(zerobuf,maxfillsize);
  972. close(f);
  973. {$I+}
  974. i:=ioresult;
  975. postprocessexecutable:=true;
  976. end;
  977. end.
  978. {
  979. $Log$
  980. Revision 1.12 1999-12-08 10:40:01 pierre
  981. + allow use of unit var in exports of DLL for win32
  982. by using direct export writing by default instead of use of DEFFILE
  983. that does not allow assembler labels that do not
  984. start with an underscore.
  985. Use -WD to force use of Deffile for Win32 DLL
  986. Revision 1.11 1999/12/06 18:21:04 peter
  987. * support !ENVVAR for long commandlines
  988. * win32/go32v2 write short pathnames to link.res so c:\Program Files\ is
  989. finally supported as installdir.
  990. Revision 1.10 1999/11/24 11:45:36 pierre
  991. * $STRIP was missign in DllCmd[1]
  992. Revision 1.9 1999/11/22 22:20:43 pierre
  993. * Def file syntax for win32 with index corrected
  994. * direct output of .edata leads to same indexes
  995. (index 5 leads to next export being 6 unless otherwise
  996. specified like for enums)
  997. Revision 1.8 1999/11/16 23:39:04 peter
  998. * use outputexedir for link.res location
  999. Revision 1.7 1999/11/15 15:01:56 pierre
  1000. + Pavel's changes to support reloc section in exes
  1001. Revision 1.6 1999/11/12 11:03:50 peter
  1002. * searchpaths changed to stringqueue object
  1003. Revision 1.5 1999/11/04 10:55:31 peter
  1004. * TSearchPathString for the string type of the searchpaths, which is
  1005. ansistring under FPC/Delphi
  1006. Revision 1.4 1999/11/02 15:06:58 peter
  1007. * import library fixes for win32
  1008. * alignment works again
  1009. Revision 1.3 1999/10/28 10:33:06 pierre
  1010. * Libs can be link serveral times
  1011. Revision 1.2 1999/10/22 14:42:40 peter
  1012. * reset linklibc
  1013. Revision 1.1 1999/10/21 14:29:38 peter
  1014. * redesigned linker object
  1015. + library support for linux (only procedures can be exported)
  1016. }