t_win32.pas 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132
  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 RelocSection then
  576. begin
  577. { ExeCmd[2]:='dlltool --as $ASBIN --dllname $EXE --output-exp exp.$$$ $RELOC $DEF';
  578. use short forms to avoid 128 char limitation problem }
  579. ExeCmd[2]:='dlltool -S $ASBIN -D $EXE -e exp.$$$ $RELOC $DEF';
  580. ExeCmd[3]:='ldw $OPT $STRIP $APPTYPE $IMAGEBASE -o $EXE $RES exp.$$$';
  581. { DllCmd[2]:='dlltool --as $ASBIN --dllname $EXE --output-exp exp.$$$ $RELOC $DEF'; }
  582. DllCmd[2]:='dlltool -S $ASBIN -D $EXE -e exp.$$$ $RELOC $DEF';
  583. DllCmd[3]:='ldw $OPT $STRIP --dll $APPTYPE $IMAGEBASE -o $EXE $RES exp.$$$';
  584. end;
  585. end;
  586. end;
  587. Function TLinkerWin32.WriteResponseFile(isdll:boolean) : Boolean;
  588. Var
  589. linkres : TLinkRes;
  590. i : longint;
  591. HPath : PStringQueueItem;
  592. s : string;
  593. linklibc : boolean;
  594. begin
  595. WriteResponseFile:=False;
  596. { Open link.res file }
  597. LinkRes.Init(outputexedir+Info.ResName);
  598. { Write path to search libraries }
  599. HPath:=current_module^.locallibrarysearchpath.First;
  600. while assigned(HPath) do
  601. begin
  602. LinkRes.Add('SEARCH_DIR('+GetShortName(HPath^.Data^)+')');
  603. HPath:=HPath^.Next;
  604. end;
  605. HPath:=LibrarySearchPath.First;
  606. while assigned(HPath) do
  607. begin
  608. LinkRes.Add('SEARCH_DIR('+GetShortName(HPath^.Data^)+')');
  609. HPath:=HPath^.Next;
  610. end;
  611. { add objectfiles, start with prt0 always }
  612. LinkRes.Add('INPUT(');
  613. if isdll then
  614. LinkRes.AddFileName(GetShortName(FindObjectFile('wdllprt0')))
  615. else
  616. LinkRes.AddFileName(GetShortName(FindObjectFile('wprt0')));
  617. while not ObjectFiles.Empty do
  618. begin
  619. s:=ObjectFiles.Get;
  620. if s<>'' then
  621. LinkRes.AddFileName(GetShortName(s));
  622. end;
  623. { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
  624. here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
  625. linklibc:=false;
  626. While not SharedLibFiles.Empty do
  627. begin
  628. S:=SharedLibFiles.Get;
  629. if s<>'c' then
  630. begin
  631. i:=Pos(target_os.sharedlibext,S);
  632. if i>0 then
  633. Delete(S,i,255);
  634. LinkRes.Add('-l'+s);
  635. end
  636. else
  637. begin
  638. LinkRes.Add('-l'+s);
  639. linklibc:=true;
  640. end;
  641. end;
  642. { be sure that libc is the last lib }
  643. if linklibc then
  644. LinkRes.Add('-lc');
  645. LinkRes.Add(')');
  646. { Write staticlibraries }
  647. if not StaticLibFiles.Empty then
  648. begin
  649. LinkRes.Add('GROUP(');
  650. While not StaticLibFiles.Empty do
  651. begin
  652. S:=StaticLibFiles.Get;
  653. LinkRes.AddFileName(GetShortName(s));
  654. end;
  655. LinkRes.Add(')');
  656. end;
  657. { Write and Close response }
  658. linkres.writetodisk;
  659. linkres.done;
  660. WriteResponseFile:=True;
  661. end;
  662. function TLinkerWin32.MakeExecutable:boolean;
  663. var
  664. binstr,
  665. cmdstr : string;
  666. found,
  667. success : boolean;
  668. i : longint;
  669. AsBinStr : string[80];
  670. StripStr,
  671. RelocStr,
  672. AppTypeStr,
  673. ImageBaseStr : string[40];
  674. begin
  675. if not(cs_link_extern in aktglobalswitches) then
  676. Message1(exec_i_linking,current_module^.exefilename^);
  677. { Create some replacements }
  678. RelocStr:='';
  679. AppTypeStr:='';
  680. ImageBaseStr:='';
  681. StripStr:='';
  682. AsBinStr:=FindExe('asw',found);
  683. if RelocSection then
  684. { RelocStr:='--base-file base.$$$';
  685. Using short form to avoid problems with 128 char limitation under Dos }
  686. RelocStr:='-b base.$$$';
  687. if apptype=at_gui then
  688. AppTypeStr:='--subsystem windows';
  689. if assigned(DLLImageBase) then
  690. ImageBaseStr:='--image-base=0x'+DLLImageBase^;
  691. if (cs_link_strip in aktglobalswitches) then
  692. StripStr:='-s';
  693. { Write used files and libraries }
  694. WriteResponseFile(false);
  695. { Call linker }
  696. success:=false;
  697. for i:=1 to 3 do
  698. begin
  699. SplitBinCmd(Info.ExeCmd[i],binstr,cmdstr);
  700. if binstr<>'' then
  701. begin
  702. Replace(cmdstr,'$EXE',current_module^.exefilename^);
  703. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  704. Replace(cmdstr,'$RES',outputexedir+Info.ResName);
  705. Replace(cmdstr,'$APPTYPE',AppTypeStr);
  706. Replace(cmdstr,'$ASBIN',AsbinStr);
  707. Replace(cmdstr,'$RELOC',RelocStr);
  708. Replace(cmdstr,'$IMAGEBASE',ImageBaseStr);
  709. Replace(cmdstr,'$STRIP',StripStr);
  710. if not DefFile.Empty {and UseDefFileForExport} then
  711. begin
  712. DefFile.WriteFile;
  713. Replace(cmdstr,'$DEF','-d '+deffile.fname);
  714. end
  715. else
  716. Replace(cmdstr,'$DEF','');
  717. success:=DoExec(FindUtil(binstr),cmdstr,(i=1),false);
  718. if not success then
  719. break;
  720. end;
  721. end;
  722. { Post process }
  723. if success then
  724. success:=PostProcessExecutable(current_module^.exefilename^,false);
  725. { Remove ReponseFile }
  726. if (success) and not(cs_link_extern in aktglobalswitches) then
  727. begin
  728. RemoveFile(outputexedir+Info.ResName);
  729. RemoveFile('base.$$$');
  730. RemoveFile('exp.$$$');
  731. end;
  732. MakeExecutable:=success; { otherwise a recursive call to link method }
  733. end;
  734. Function TLinkerWin32.MakeSharedLibrary:boolean;
  735. var
  736. binstr,
  737. cmdstr : string;
  738. found,
  739. success : boolean;
  740. i : longint;
  741. AsBinStr : string[80];
  742. StripStr,
  743. RelocStr,
  744. AppTypeStr,
  745. ImageBaseStr : string[40];
  746. begin
  747. MakeSharedLibrary:=false;
  748. if not(cs_link_extern in aktglobalswitches) then
  749. Message1(exec_i_linking,current_module^.sharedlibfilename^);
  750. { Create some replacements }
  751. RelocStr:='';
  752. AppTypeStr:='';
  753. ImageBaseStr:='';
  754. StripStr:='';
  755. AsBinStr:=FindExe('asw',found);
  756. if RelocSection then
  757. { RelocStr:='--base-file base.$$$';
  758. Using short form to avoid problems with 128 char limitation under Dos }
  759. RelocStr:='-b base.$$$';
  760. if apptype=at_gui then
  761. AppTypeStr:='--subsystem windows';
  762. if assigned(DLLImageBase) then
  763. ImageBaseStr:='--image-base=0x'+DLLImageBase^;
  764. if (cs_link_strip in aktglobalswitches) then
  765. StripStr:='-s';
  766. { Write used files and libraries }
  767. WriteResponseFile(true);
  768. { Call linker }
  769. success:=false;
  770. for i:=1to 3 do
  771. begin
  772. SplitBinCmd(Info.DllCmd[i],binstr,cmdstr);
  773. if binstr<>'' then
  774. begin
  775. Replace(cmdstr,'$EXE',current_module^.sharedlibfilename^);
  776. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  777. Replace(cmdstr,'$RES',outputexedir+Info.ResName);
  778. Replace(cmdstr,'$APPTYPE',AppTypeStr);
  779. Replace(cmdstr,'$ASBIN',AsbinStr);
  780. Replace(cmdstr,'$RELOC',RelocStr);
  781. Replace(cmdstr,'$IMAGEBASE',ImageBaseStr);
  782. Replace(cmdstr,'$STRIP',StripStr);
  783. if not DefFile.Empty {and UseDefFileForExport} then
  784. begin
  785. DefFile.WriteFile;
  786. Replace(cmdstr,'$DEF','-d '+deffile.fname);
  787. end
  788. else
  789. Replace(cmdstr,'$DEF','');
  790. success:=DoExec(FindUtil(binstr),cmdstr,(i=1),false);
  791. if not success then
  792. break;
  793. end;
  794. end;
  795. { Post process }
  796. if success then
  797. success:=PostProcessExecutable(current_module^.sharedlibfilename^,true);
  798. { Remove ReponseFile }
  799. if (success) and not(cs_link_extern in aktglobalswitches) then
  800. begin
  801. RemoveFile(outputexedir+Info.ResName);
  802. RemoveFile('base.$$$');
  803. RemoveFile('exp.$$$');
  804. end;
  805. MakeSharedLibrary:=success; { otherwise a recursive call to link method }
  806. end;
  807. function tlinkerwin32.postprocessexecutable(const fn : string;isdll:boolean):boolean;
  808. type
  809. tdosheader = packed record
  810. e_magic : word;
  811. e_cblp : word;
  812. e_cp : word;
  813. e_crlc : word;
  814. e_cparhdr : word;
  815. e_minalloc : word;
  816. e_maxalloc : word;
  817. e_ss : word;
  818. e_sp : word;
  819. e_csum : word;
  820. e_ip : word;
  821. e_cs : word;
  822. e_lfarlc : word;
  823. e_ovno : word;
  824. e_res : array[0..3] of word;
  825. e_oemid : word;
  826. e_oeminfo : word;
  827. e_res2 : array[0..9] of word;
  828. e_lfanew : longint;
  829. end;
  830. tpeheader = packed record
  831. PEMagic : array[0..3] of char;
  832. Machine : word;
  833. NumberOfSections : word;
  834. TimeDateStamp : longint;
  835. PointerToSymbolTable : longint;
  836. NumberOfSymbols : longint;
  837. SizeOfOptionalHeader : word;
  838. Characteristics : word;
  839. Magic : word;
  840. MajorLinkerVersion : byte;
  841. MinorLinkerVersion : byte;
  842. SizeOfCode : longint;
  843. SizeOfInitializedData : longint;
  844. SizeOfUninitializedData : longint;
  845. AddressOfEntryPoint : longint;
  846. BaseOfCode : longint;
  847. BaseOfData : longint;
  848. ImageBase : longint;
  849. SectionAlignment : longint;
  850. FileAlignment : longint;
  851. MajorOperatingSystemVersion : word;
  852. MinorOperatingSystemVersion : word;
  853. MajorImageVersion : word;
  854. MinorImageVersion : word;
  855. MajorSubsystemVersion : word;
  856. MinorSubsystemVersion : word;
  857. Reserved1 : longint;
  858. SizeOfImage : longint;
  859. SizeOfHeaders : longint;
  860. CheckSum : longint;
  861. Subsystem : word;
  862. DllCharacteristics : word;
  863. SizeOfStackReserve : longint;
  864. SizeOfStackCommit : longint;
  865. SizeOfHeapReserve : longint;
  866. SizeOfHeapCommit : longint;
  867. LoaderFlags : longint;
  868. NumberOfRvaAndSizes : longint;
  869. DataDirectory : array[1..$80] of byte;
  870. end;
  871. tcoffsechdr=packed record
  872. name : array[0..7] of char;
  873. vsize : longint;
  874. rvaofs : longint;
  875. datalen : longint;
  876. datapos : longint;
  877. relocpos : longint;
  878. lineno1 : longint;
  879. nrelocs : word;
  880. lineno2 : word;
  881. flags : longint;
  882. end;
  883. psecfill=^tsecfill;
  884. tsecfill=record
  885. fillpos,
  886. fillsize : longint;
  887. next : psecfill;
  888. end;
  889. var
  890. f : file;
  891. dosheader : tdosheader;
  892. peheader : tpeheader;
  893. firstsecpos,
  894. maxfillsize,
  895. i,l,peheaderpos : longint;
  896. coffsec : tcoffsechdr;
  897. secroot,hsecroot : psecfill;
  898. zerobuf : pointer;
  899. begin
  900. postprocessexecutable:=false;
  901. { when -s is used or it's a dll then quit }
  902. if (cs_link_extern in aktglobalswitches) then
  903. begin
  904. postprocessexecutable:=true;
  905. exit;
  906. end;
  907. { open file }
  908. assign(f,fn);
  909. {$I-}
  910. reset(f,1);
  911. if ioresult<>0 then
  912. Message1(execinfo_f_cant_open_executable,fn);
  913. { read headers }
  914. blockread(f,dosheader,sizeof(tdosheader));
  915. peheaderpos:=dosheader.e_lfanew;
  916. seek(f,peheaderpos);
  917. blockread(f,peheader,sizeof(tpeheader));
  918. { write info }
  919. Message1(execinfo_x_codesize,tostr(peheader.SizeOfCode));
  920. Message1(execinfo_x_initdatasize,tostr(peheader.SizeOfInitializedData));
  921. Message1(execinfo_x_uninitdatasize,tostr(peheader.SizeOfUninitializedData));
  922. { change stack size (PM) }
  923. { I am not sure that the default value is adequate !! }
  924. peheader.SizeOfStackReserve:=stacksize;
  925. { change the header }
  926. { sub system }
  927. { gui=2 }
  928. { cui=3 }
  929. if apptype=at_gui then
  930. peheader.Subsystem:=2
  931. else if apptype=at_cui then
  932. peheader.Subsystem:=3;
  933. if dllversion<>'' then
  934. begin
  935. peheader.MajorImageVersion:=dllmajor;
  936. peheader.MinorImageVersion:=dllminor;
  937. end;
  938. seek(f,peheaderpos);
  939. blockwrite(f,peheader,sizeof(tpeheader));
  940. if ioresult<>0 then
  941. Message1(execinfo_f_cant_process_executable,fn);
  942. seek(f,peheaderpos);
  943. blockread(f,peheader,sizeof(tpeheader));
  944. { write the value after the change }
  945. Message1(execinfo_x_stackreserve,tostr(peheader.SizeOfStackReserve));
  946. Message1(execinfo_x_stackcommit,tostr(peheader.SizeOfStackCommit));
  947. { read section info }
  948. maxfillsize:=0;
  949. firstsecpos:=0;
  950. secroot:=nil;
  951. for l:=1to peheader.NumberOfSections do
  952. begin
  953. blockread(f,coffsec,sizeof(tcoffsechdr));
  954. if coffsec.datapos>0 then
  955. begin
  956. if secroot=nil then
  957. firstsecpos:=coffsec.datapos;
  958. new(hsecroot);
  959. hsecroot^.fillpos:=coffsec.datapos+coffsec.vsize;
  960. hsecroot^.fillsize:=coffsec.datalen-coffsec.vsize;
  961. hsecroot^.next:=secroot;
  962. secroot:=hsecroot;
  963. if secroot^.fillsize>maxfillsize then
  964. maxfillsize:=secroot^.fillsize;
  965. end;
  966. end;
  967. if firstsecpos>0 then
  968. begin
  969. l:=firstsecpos-filepos(f);
  970. if l>maxfillsize then
  971. maxfillsize:=l;
  972. end
  973. else
  974. l:=0;
  975. { get zero buffer }
  976. getmem(zerobuf,maxfillsize);
  977. fillchar(zerobuf^,maxfillsize,0);
  978. { zero from sectioninfo until first section }
  979. blockwrite(f,zerobuf^,l);
  980. { zero section alignments }
  981. while assigned(secroot) do
  982. begin
  983. seek(f,secroot^.fillpos);
  984. blockwrite(f,zerobuf^,secroot^.fillsize);
  985. hsecroot:=secroot;
  986. secroot:=secroot^.next;
  987. dispose(hsecroot);
  988. end;
  989. freemem(zerobuf,maxfillsize);
  990. close(f);
  991. {$I+}
  992. i:=ioresult;
  993. postprocessexecutable:=true;
  994. end;
  995. end.
  996. {
  997. $Log$
  998. Revision 1.13 1999-12-20 23:23:30 pierre
  999. + $description $version
  1000. Revision 1.12 1999/12/08 10:40:01 pierre
  1001. + allow use of unit var in exports of DLL for win32
  1002. by using direct export writing by default instead of use of DEFFILE
  1003. that does not allow assembler labels that do not
  1004. start with an underscore.
  1005. Use -WD to force use of Deffile for Win32 DLL
  1006. Revision 1.11 1999/12/06 18:21:04 peter
  1007. * support !ENVVAR for long commandlines
  1008. * win32/go32v2 write short pathnames to link.res so c:\Program Files\ is
  1009. finally supported as installdir.
  1010. Revision 1.10 1999/11/24 11:45:36 pierre
  1011. * $STRIP was missign in DllCmd[1]
  1012. Revision 1.9 1999/11/22 22:20:43 pierre
  1013. * Def file syntax for win32 with index corrected
  1014. * direct output of .edata leads to same indexes
  1015. (index 5 leads to next export being 6 unless otherwise
  1016. specified like for enums)
  1017. Revision 1.8 1999/11/16 23:39:04 peter
  1018. * use outputexedir for link.res location
  1019. Revision 1.7 1999/11/15 15:01:56 pierre
  1020. + Pavel's changes to support reloc section in exes
  1021. Revision 1.6 1999/11/12 11:03:50 peter
  1022. * searchpaths changed to stringqueue object
  1023. Revision 1.5 1999/11/04 10:55:31 peter
  1024. * TSearchPathString for the string type of the searchpaths, which is
  1025. ansistring under FPC/Delphi
  1026. Revision 1.4 1999/11/02 15:06:58 peter
  1027. * import library fixes for win32
  1028. * alignment works again
  1029. Revision 1.3 1999/10/28 10:33:06 pierre
  1030. * Libs can be link serveral times
  1031. Revision 1.2 1999/10/22 14:42:40 peter
  1032. * reset linklibc
  1033. Revision 1.1 1999/10/21 14:29:38 peter
  1034. * redesigned linker object
  1035. + library support for linux (only procedures can be exported)
  1036. }