t_win32.pas 40 KB

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