t_win32.pas 39 KB

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