t_win32.pas 41 KB

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