coff-objfmt.c 90 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522
  1. /*
  2. * COFF (DJGPP) object format
  3. *
  4. * Copyright (C) 2002-2007 Peter Johnson
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
  19. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  20. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  21. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  22. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  23. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  24. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  25. * POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #include <util.h>
  28. #include <time.h>
  29. #include <libyasm.h>
  30. #include "coff-objfmt.h"
  31. #define REGULAR_OUTBUF_SIZE 1024
  32. /* Defining this to 0 sets all section VMA's to 0 rather than as the same as
  33. * the LMA. According to the DJGPP COFF Spec, this should be set to 1
  34. * (VMA=LMA), and indeed DJGPP's GCC output shows VMA=LMA. However, NASM
  35. * outputs VMA=0 (as if this was 0), and GNU objdump output looks a lot nicer
  36. * with VMA=0. Who's right? This is #defined as changing this setting affects
  37. * several places in the code.
  38. */
  39. #define COFF_SET_VMA (!objfmt_coff->win32)
  40. #define COFF_MACHINE_I386 0x014C
  41. #define COFF_MACHINE_AMD64 0x8664
  42. #define COFF_F_LNNO 0x0004 /* line number info NOT present */
  43. #define COFF_F_LSYMS 0x0008 /* local symbols NOT present */
  44. #define COFF_F_AR32WR 0x0100 /* 32-bit little endian file */
  45. typedef struct coff_reloc {
  46. yasm_reloc reloc;
  47. enum {
  48. COFF_RELOC_ABSOLUTE = 0, /* absolute, no reloc needed */
  49. /* I386 relocations */
  50. COFF_RELOC_I386_ADDR16 = 0x1, /* 16-bit absolute reference */
  51. COFF_RELOC_I386_REL16 = 0x2, /* 16-bit PC-relative reference */
  52. COFF_RELOC_I386_ADDR32 = 0x6, /* 32-bit absolute reference */
  53. COFF_RELOC_I386_ADDR32NB = 0x7, /* 32-bit absolute ref w/o base */
  54. COFF_RELOC_I386_SEG12 = 0x9, /* 16-bit absolute segment ref */
  55. COFF_RELOC_I386_SECTION = 0xA, /* section index */
  56. COFF_RELOC_I386_SECREL = 0xB, /* offset from start of segment */
  57. COFF_RELOC_I386_TOKEN = 0xC, /* CLR metadata token */
  58. COFF_RELOC_I386_SECREL7 = 0xD, /* 7-bit offset from base of sect */
  59. COFF_RELOC_I386_REL32 = 0x14, /* 32-bit PC-relative reference */
  60. /* AMD64 relocations */
  61. COFF_RELOC_AMD64_ADDR64 = 0x1, /* 64-bit address (VA) */
  62. COFF_RELOC_AMD64_ADDR32 = 0x2, /* 32-bit address (VA) */
  63. COFF_RELOC_AMD64_ADDR32NB = 0x3, /* 32-bit address w/o base (RVA) */
  64. COFF_RELOC_AMD64_REL32 = 0x4, /* 32-bit relative (0 byte dist) */
  65. COFF_RELOC_AMD64_REL32_1 = 0x5, /* 32-bit relative (1 byte dist) */
  66. COFF_RELOC_AMD64_REL32_2 = 0x6, /* 32-bit relative (2 byte dist) */
  67. COFF_RELOC_AMD64_REL32_3 = 0x7, /* 32-bit relative (3 byte dist) */
  68. COFF_RELOC_AMD64_REL32_4 = 0x8, /* 32-bit relative (4 byte dist) */
  69. COFF_RELOC_AMD64_REL32_5 = 0x9, /* 32-bit relative (5 byte dist) */
  70. COFF_RELOC_AMD64_SECTION = 0xA, /* section index */
  71. COFF_RELOC_AMD64_SECREL = 0xB, /* 32-bit offset from base of sect */
  72. COFF_RELOC_AMD64_SECREL7 = 0xC, /* 7-bit offset from base of sect */
  73. COFF_RELOC_AMD64_TOKEN = 0xD /* CLR metadata token */
  74. } type; /* type of relocation */
  75. } coff_reloc;
  76. #define COFF_STYP_TEXT 0x00000020UL
  77. #define COFF_STYP_DATA 0x00000040UL
  78. #define COFF_STYP_BSS 0x00000080UL
  79. #define COFF_STYP_INFO 0x00000200UL
  80. #define COFF_STYP_STD_MASK 0x000003FFUL
  81. #define COFF_STYP_ALIGN_MASK 0x00F00000UL
  82. #define COFF_STYP_ALIGN_SHIFT 20
  83. #define COFF_STYP_NRELOC_OVFL 0x01000000UL
  84. #define COFF_STYP_DISCARD 0x02000000UL
  85. #define COFF_STYP_NOCACHE 0x04000000UL
  86. #define COFF_STYP_NOPAGE 0x08000000UL
  87. #define COFF_STYP_SHARED 0x10000000UL
  88. #define COFF_STYP_EXECUTE 0x20000000UL
  89. #define COFF_STYP_READ 0x40000000UL
  90. #define COFF_STYP_WRITE 0x80000000UL
  91. #define COFF_STYP_WIN32_MASK 0xFF000000UL
  92. #define COFF_FLAG_NOBASE (1UL<<0) /* Use no-base (NB) relocs */
  93. typedef struct coff_section_data {
  94. /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */
  95. unsigned int scnum; /* section number (1=first section) */
  96. unsigned long flags; /* section flags (see COFF_STYP_* above) */
  97. unsigned long addr; /* starting memory address (first section -> 0) */
  98. unsigned long scnptr; /* file ptr to raw data */
  99. unsigned long size; /* size of raw data (section data) in bytes */
  100. unsigned long relptr; /* file ptr to relocation */
  101. unsigned long nreloc; /* number of relocation entries >64k -> error */
  102. unsigned long flags2; /* internal flags (see COFF_FLAG_* above) */
  103. unsigned long strtab_name; /* strtab offset of name if name > 8 chars */
  104. int isdebug; /* is a debug section? */
  105. } coff_section_data;
  106. typedef enum coff_symrec_sclass {
  107. COFF_SCL_EFCN = 0xff, /* physical end of function */
  108. COFF_SCL_NULL = 0,
  109. COFF_SCL_AUTO = 1, /* automatic variable */
  110. COFF_SCL_EXT = 2, /* external symbol */
  111. COFF_SCL_STAT = 3, /* static */
  112. COFF_SCL_REG = 4, /* register variable */
  113. COFF_SCL_EXTDEF = 5, /* external definition */
  114. COFF_SCL_LABEL = 6, /* label */
  115. COFF_SCL_ULABEL = 7, /* undefined label */
  116. COFF_SCL_MOS = 8, /* member of structure */
  117. COFF_SCL_ARG = 9, /* function argument */
  118. COFF_SCL_STRTAG = 10, /* structure tag */
  119. COFF_SCL_MOU = 11, /* member of union */
  120. COFF_SCL_UNTAG = 12, /* union tag */
  121. COFF_SCL_TPDEF = 13, /* type definition */
  122. COFF_SCL_USTATIC = 14, /* undefined static */
  123. COFF_SCL_ENTAG = 15, /* enumeration tag */
  124. COFF_SCL_MOE = 16, /* member of enumeration */
  125. COFF_SCL_REGPARM = 17, /* register parameter */
  126. COFF_SCL_FIELD = 18, /* bit field */
  127. COFF_SCL_AUTOARG = 19, /* auto argument */
  128. COFF_SCL_LASTENT = 20, /* dummy entry (end of block) */
  129. COFF_SCL_BLOCK = 100, /* ".bb" or ".eb" */
  130. COFF_SCL_FCN = 101, /* ".bf" or ".ef" */
  131. COFF_SCL_EOS = 102, /* end of structure */
  132. COFF_SCL_FILE = 103, /* file name */
  133. COFF_SCL_LINE = 104, /* line # reformatted as symbol table entry */
  134. COFF_SCL_ALIAS = 105, /* duplicate tag */
  135. COFF_SCL_HIDDEN = 106 /* ext symbol in dmert public lib */
  136. } coff_symrec_sclass;
  137. typedef union coff_symtab_auxent {
  138. /* no data needed for section symbol auxent, all info avail from sym */
  139. /*@owned@*/ char *fname; /* filename aux entry */
  140. } coff_symtab_auxent;
  141. typedef enum coff_symtab_auxtype {
  142. COFF_SYMTAB_AUX_NONE = 0,
  143. COFF_SYMTAB_AUX_SECT,
  144. COFF_SYMTAB_AUX_FILE
  145. } coff_symtab_auxtype;
  146. typedef struct coff_symrec_data {
  147. int forcevis; /* force visibility in symbol table */
  148. unsigned long index; /* assigned COFF symbol table index */
  149. unsigned int type; /* type */
  150. coff_symrec_sclass sclass; /* storage class */
  151. int numaux; /* number of auxiliary entries */
  152. coff_symtab_auxtype auxtype; /* type of aux entries */
  153. coff_symtab_auxent aux[1]; /* actually may be any size (including 0) */
  154. } coff_symrec_data;
  155. typedef struct yasm_objfmt_coff {
  156. yasm_objfmt_base objfmt; /* base structure */
  157. unsigned int parse_scnum; /* sect numbering in parser */
  158. int win32; /* nonzero for win32/64 output */
  159. int win64; /* nonzero for win64 output */
  160. unsigned int machine; /* COFF machine to use */
  161. coff_symrec_data *filesym_data; /* Data for .file symbol */
  162. /* data for .def/.endef and related directives */
  163. coff_symrec_data *def_sym; /* symbol specified by .def */
  164. /* data for win64 proc_frame and related directives */
  165. unsigned long proc_frame; /* Line number of start of proc, or 0 */
  166. unsigned long done_prolog; /* Line number of end of prologue, or 0 */
  167. /*@null@*/ coff_unwind_info *unwind; /* Unwind info */
  168. yasm_symrec *ssym_imagebase; /* ..imagebase symbol for win64 */
  169. } yasm_objfmt_coff;
  170. typedef struct coff_objfmt_output_info {
  171. yasm_object *object;
  172. yasm_objfmt_coff *objfmt_coff;
  173. yasm_errwarns *errwarns;
  174. /*@dependent@*/ FILE *f;
  175. /*@only@*/ unsigned char *buf;
  176. yasm_section *sect;
  177. /*@dependent@*/ coff_section_data *csd;
  178. unsigned long addr; /* start of next section */
  179. unsigned long indx; /* current symbol index */
  180. int all_syms; /* outputting all symbols? */
  181. unsigned long strtab_offset; /* current string table offset */
  182. } coff_objfmt_output_info;
  183. static void coff_section_data_destroy(/*@only@*/ void *d);
  184. static void coff_section_data_print(void *data, FILE *f, int indent_level);
  185. static const yasm_assoc_data_callback coff_section_data_cb = {
  186. coff_section_data_destroy,
  187. coff_section_data_print
  188. };
  189. static void coff_symrec_data_destroy(/*@only@*/ void *d);
  190. static void coff_symrec_data_print(void *data, FILE *f, int indent_level);
  191. static const yasm_assoc_data_callback coff_symrec_data_cb = {
  192. coff_symrec_data_destroy,
  193. coff_symrec_data_print
  194. };
  195. /* Bytecode callback function prototypes */
  196. static void win32_sxdata_bc_destroy(void *contents);
  197. static void win32_sxdata_bc_print(const void *contents, FILE *f,
  198. int indent_level);
  199. static int win32_sxdata_bc_calc_len
  200. (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
  201. static int win32_sxdata_bc_tobytes
  202. (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
  203. yasm_output_value_func output_value,
  204. /*@null@*/ yasm_output_reloc_func output_reloc);
  205. /* Bytecode callback structures */
  206. static const yasm_bytecode_callback win32_sxdata_bc_callback = {
  207. win32_sxdata_bc_destroy,
  208. win32_sxdata_bc_print,
  209. yasm_bc_finalize_common,
  210. NULL,
  211. win32_sxdata_bc_calc_len,
  212. yasm_bc_expand_common,
  213. win32_sxdata_bc_tobytes,
  214. 0
  215. };
  216. yasm_objfmt_module yasm_coff_LTX_objfmt;
  217. yasm_objfmt_module yasm_win32_LTX_objfmt;
  218. yasm_objfmt_module yasm_win64_LTX_objfmt;
  219. static /*@dependent@*/ coff_symrec_data *
  220. coff_objfmt_sym_set_data(yasm_symrec *sym, coff_symrec_sclass sclass,
  221. int numaux, coff_symtab_auxtype auxtype)
  222. {
  223. coff_symrec_data *sym_data;
  224. sym_data = yasm_xmalloc(sizeof(coff_symrec_data) +
  225. (numaux-1)*sizeof(coff_symtab_auxent));
  226. sym_data->forcevis = 0;
  227. sym_data->index = 0;
  228. sym_data->type = 0;
  229. sym_data->sclass = sclass;
  230. sym_data->numaux = numaux;
  231. sym_data->auxtype = auxtype;
  232. yasm_symrec_add_data(sym, &coff_symrec_data_cb, sym_data);
  233. return sym_data;
  234. }
  235. static yasm_objfmt_coff *
  236. coff_common_create(yasm_object *object)
  237. {
  238. yasm_objfmt_coff *objfmt_coff = yasm_xmalloc(sizeof(yasm_objfmt_coff));
  239. yasm_symrec *filesym;
  240. /* Only support x86 arch */
  241. if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") != 0) {
  242. yasm_xfree(objfmt_coff);
  243. return NULL;
  244. }
  245. objfmt_coff->parse_scnum = 1; /* section numbering starts at 1 */
  246. /* FIXME: misuse of NULL bytecode here; it works, but only barely. */
  247. filesym = yasm_symtab_define_special(object->symtab, ".file",
  248. YASM_SYM_GLOBAL);
  249. objfmt_coff->filesym_data =
  250. coff_objfmt_sym_set_data(filesym, COFF_SCL_FILE, 1,
  251. COFF_SYMTAB_AUX_FILE);
  252. /* Filename is set in coff_objfmt_output */
  253. objfmt_coff->filesym_data->aux[0].fname = NULL;
  254. objfmt_coff->proc_frame = 0;
  255. objfmt_coff->done_prolog = 0;
  256. objfmt_coff->unwind = NULL;
  257. objfmt_coff->ssym_imagebase = NULL;
  258. return objfmt_coff;
  259. }
  260. static yasm_objfmt *
  261. coff_objfmt_create(yasm_object *object)
  262. {
  263. yasm_objfmt_coff *objfmt_coff = coff_common_create(object);
  264. if (objfmt_coff) {
  265. /* Support x86 and amd64 machines of x86 arch */
  266. if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), "x86") == 0)
  267. objfmt_coff->machine = COFF_MACHINE_I386;
  268. else if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
  269. "amd64") == 0)
  270. objfmt_coff->machine = COFF_MACHINE_AMD64;
  271. else {
  272. yasm_xfree(objfmt_coff);
  273. return NULL;
  274. }
  275. objfmt_coff->objfmt.module = &yasm_coff_LTX_objfmt;
  276. objfmt_coff->win32 = 0;
  277. objfmt_coff->win64 = 0;
  278. }
  279. return (yasm_objfmt *)objfmt_coff;
  280. }
  281. static yasm_objfmt *
  282. win32_objfmt_create(yasm_object *object)
  283. {
  284. yasm_objfmt_coff *objfmt_coff = coff_common_create(object);
  285. if (objfmt_coff) {
  286. /* Support x86 and amd64 machines of x86 arch.
  287. * (amd64 machine supported for backwards compatibility)
  288. */
  289. if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
  290. "x86") == 0) {
  291. objfmt_coff->machine = COFF_MACHINE_I386;
  292. objfmt_coff->objfmt.module = &yasm_win32_LTX_objfmt;
  293. objfmt_coff->win64 = 0;
  294. } else if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
  295. "amd64") == 0) {
  296. objfmt_coff->machine = COFF_MACHINE_AMD64;
  297. objfmt_coff->objfmt.module = &yasm_win64_LTX_objfmt;
  298. objfmt_coff->win64 = 1;
  299. } else {
  300. yasm_xfree(objfmt_coff);
  301. return NULL;
  302. }
  303. objfmt_coff->win32 = 1;
  304. /* Define a @feat.00 symbol for win32 safeseh handling */
  305. if (!objfmt_coff->win64) {
  306. yasm_symrec *feat00;
  307. coff_symrec_data *sym_data;
  308. feat00 = yasm_symtab_define_equ(object->symtab, "@feat.00",
  309. yasm_expr_create_ident(yasm_expr_int(
  310. yasm_intnum_create_uint(1)), 0), 0);
  311. sym_data = coff_objfmt_sym_set_data(feat00, COFF_SCL_STAT, 0,
  312. COFF_SYMTAB_AUX_NONE);
  313. sym_data->forcevis = 1;
  314. }
  315. }
  316. return (yasm_objfmt *)objfmt_coff;
  317. }
  318. static yasm_objfmt *
  319. win64_objfmt_create(yasm_object *object)
  320. {
  321. yasm_objfmt_coff *objfmt_coff = coff_common_create(object);
  322. if (objfmt_coff) {
  323. /* Support amd64 machine of x86 arch */
  324. if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
  325. "amd64") == 0) {
  326. objfmt_coff->machine = COFF_MACHINE_AMD64;
  327. } else {
  328. yasm_xfree(objfmt_coff);
  329. return NULL;
  330. }
  331. objfmt_coff->objfmt.module = &yasm_win64_LTX_objfmt;
  332. objfmt_coff->win32 = 1;
  333. objfmt_coff->win64 = 1;
  334. objfmt_coff->ssym_imagebase =
  335. yasm_symtab_define_label(object->symtab, "..imagebase", NULL, 0, 0);
  336. }
  337. return (yasm_objfmt *)objfmt_coff;
  338. }
  339. static void
  340. coff_objfmt_init_new_section(yasm_section *sect, unsigned long line)
  341. {
  342. yasm_object *object = yasm_section_get_object(sect);
  343. const char *sectname = yasm_section_get_name(sect);
  344. yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
  345. coff_section_data *data;
  346. yasm_symrec *sym;
  347. data = yasm_xmalloc(sizeof(coff_section_data));
  348. data->scnum = objfmt_coff->parse_scnum++;
  349. data->flags = 0;
  350. data->addr = 0;
  351. data->scnptr = 0;
  352. data->size = 0;
  353. data->relptr = 0;
  354. data->nreloc = 0;
  355. data->flags2 = 0;
  356. data->strtab_name = 0;
  357. data->isdebug = 0;
  358. if (yasm__strncasecmp(sectname, ".debug", 6)==0) {
  359. data->flags = COFF_STYP_DATA;
  360. if (objfmt_coff->win32)
  361. data->flags |= COFF_STYP_DISCARD|COFF_STYP_READ;
  362. data->isdebug = 1;
  363. } else
  364. data->flags = COFF_STYP_TEXT;
  365. yasm_section_add_data(sect, &coff_section_data_cb, data);
  366. sym = yasm_symtab_define_label(object->symtab, sectname,
  367. yasm_section_bcs_first(sect), 1, line);
  368. yasm_symrec_declare(sym, YASM_SYM_GLOBAL, line);
  369. coff_objfmt_sym_set_data(sym, COFF_SCL_STAT, 1, COFF_SYMTAB_AUX_SECT);
  370. data->sym = sym;
  371. }
  372. static int
  373. coff_objfmt_set_section_addr(yasm_section *sect, /*@null@*/ void *d)
  374. {
  375. /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
  376. /*@dependent@*/ /*@null@*/ coff_section_data *csd;
  377. assert(info != NULL);
  378. csd = yasm_section_get_data(sect, &coff_section_data_cb);
  379. assert(csd != NULL);
  380. csd->addr = info->addr;
  381. info->addr += yasm_bc_next_offset(yasm_section_bcs_last(sect));
  382. return 0;
  383. }
  384. static int
  385. coff_objfmt_output_value(yasm_value *value, unsigned char *buf,
  386. unsigned int destsize, unsigned long offset,
  387. yasm_bytecode *bc, int warn, /*@null@*/ void *d)
  388. {
  389. /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
  390. yasm_objfmt_coff *objfmt_coff;
  391. /*@only@*/ /*@null@*/ yasm_intnum *dist = NULL;
  392. /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
  393. unsigned long intn_val, intn_minus;
  394. int retval;
  395. unsigned int valsize = value->size;
  396. assert(info != NULL);
  397. objfmt_coff = info->objfmt_coff;
  398. if (value->abs)
  399. value->abs = yasm_expr_simplify(value->abs, 1);
  400. /* Try to output constant and PC-relative section-local first.
  401. * Note this does NOT output any value with a SEG, WRT, external,
  402. * cross-section, or non-PC-relative reference (those are handled below).
  403. */
  404. switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
  405. info->object->arch)) {
  406. case -1:
  407. return 1;
  408. case 0:
  409. break;
  410. default:
  411. return 0;
  412. }
  413. /* Handle other expressions, with relocation if necessary */
  414. if (value->rshift > 0
  415. || (value->seg_of && (value->wrt || value->curpos_rel))
  416. || (value->section_rel && (value->wrt || value->curpos_rel))) {
  417. yasm_error_set(YASM_ERROR_TOO_COMPLEX,
  418. N_("coff: relocation too complex"));
  419. return 1;
  420. }
  421. intn_val = 0;
  422. intn_minus = 0;
  423. if (value->rel) {
  424. yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel);
  425. /*@dependent@*/ /*@null@*/ yasm_symrec *sym = value->rel;
  426. unsigned long addr;
  427. coff_reloc *reloc;
  428. int nobase = info->csd->flags2 & COFF_FLAG_NOBASE;
  429. /* Sometimes we want the relocation to be generated against one
  430. * symbol but the value generated correspond to a different symbol.
  431. * This is done through (sym being referenced) WRT (sym used for
  432. * reloc). Note both syms need to be in the same section!
  433. */
  434. if (value->wrt && value->wrt == objfmt_coff->ssym_imagebase)
  435. nobase = 1;
  436. else if (value->wrt) {
  437. /*@dependent@*/ /*@null@*/ yasm_bytecode *rel_precbc, *wrt_precbc;
  438. if (!yasm_symrec_get_label(sym, &rel_precbc)
  439. || !yasm_symrec_get_label(value->wrt, &wrt_precbc)) {
  440. yasm_error_set(YASM_ERROR_TOO_COMPLEX,
  441. N_("coff: wrt expression too complex"));
  442. return 1;
  443. }
  444. dist = yasm_calc_bc_dist(wrt_precbc, rel_precbc);
  445. if (!dist) {
  446. yasm_error_set(YASM_ERROR_TOO_COMPLEX,
  447. N_("coff: cannot wrt across sections"));
  448. return 1;
  449. }
  450. sym = value->wrt;
  451. }
  452. if (vis & YASM_SYM_COMMON) {
  453. /* In standard COFF, COMMON symbols have their length added in */
  454. if (!objfmt_coff->win32) {
  455. /*@dependent@*/ /*@null@*/ yasm_expr **csize_expr;
  456. /*@dependent@*/ /*@null@*/ yasm_intnum *common_size;
  457. csize_expr = yasm_symrec_get_common_size(sym);
  458. assert(csize_expr != NULL);
  459. common_size = yasm_expr_get_intnum(csize_expr, 1);
  460. if (!common_size) {
  461. yasm_error_set(YASM_ERROR_TOO_COMPLEX,
  462. N_("coff: common size too complex"));
  463. return 1;
  464. }
  465. if (yasm_intnum_sign(common_size) < 0) {
  466. yasm_error_set(YASM_ERROR_VALUE,
  467. N_("coff: common size is negative"));
  468. return 1;
  469. }
  470. intn_val += yasm_intnum_get_uint(common_size);
  471. }
  472. } else if (!(vis & YASM_SYM_EXTERN) && !objfmt_coff->win64) {
  473. /*@dependent@*/ /*@null@*/ yasm_bytecode *sym_precbc;
  474. /* Local symbols need relocation to their section's start */
  475. if (yasm_symrec_get_label(sym, &sym_precbc)) {
  476. yasm_section *sym_sect = yasm_bc_get_section(sym_precbc);
  477. /*@null@*/ coff_section_data *sym_csd;
  478. sym_csd = yasm_section_get_data(sym_sect,
  479. &coff_section_data_cb);
  480. assert(sym_csd != NULL);
  481. sym = sym_csd->sym;
  482. intn_val = yasm_bc_next_offset(sym_precbc);
  483. if (COFF_SET_VMA)
  484. intn_val += sym_csd->addr;
  485. }
  486. }
  487. if (value->curpos_rel) {
  488. /* For standard COFF, need to adjust to start of section, e.g.
  489. * subtract out the bytecode offset.
  490. * For Win32 COFF, need to adjust based on value size and position.
  491. * For Win64 COFF that's IP-relative, adjust to next bytecode;
  492. * the difference between the offset+destsize and BC length is
  493. * taken care of by special relocation types.
  494. */
  495. if (objfmt_coff->win64 && value->ip_rel)
  496. intn_val += bc->len*bc->mult_int;
  497. else if (objfmt_coff->win32)
  498. intn_val += offset+destsize;
  499. else
  500. intn_minus = bc->offset;
  501. }
  502. if (value->seg_of) {
  503. /* Segment generation; zero value. */
  504. intn_val = 0;
  505. intn_minus = 0;
  506. }
  507. /* Generate reloc */
  508. reloc = yasm_xmalloc(sizeof(coff_reloc));
  509. addr = bc->offset + offset;
  510. if (COFF_SET_VMA)
  511. addr += info->addr;
  512. reloc->reloc.addr = yasm_intnum_create_uint(addr);
  513. reloc->reloc.sym = sym;
  514. if (value->curpos_rel) {
  515. if (objfmt_coff->machine == COFF_MACHINE_I386) {
  516. if (valsize == 32)
  517. reloc->type = COFF_RELOC_I386_REL32;
  518. else {
  519. yasm_error_set(YASM_ERROR_TYPE,
  520. N_("coff: invalid relocation size"));
  521. return 1;
  522. }
  523. } else if (objfmt_coff->machine == COFF_MACHINE_AMD64) {
  524. if (valsize != 32) {
  525. yasm_error_set(YASM_ERROR_TYPE,
  526. N_("coff: invalid relocation size"));
  527. return 1;
  528. }
  529. if (!value->ip_rel)
  530. reloc->type = COFF_RELOC_AMD64_REL32;
  531. else switch (bc->len*bc->mult_int - (offset+destsize)) {
  532. case 0:
  533. reloc->type = COFF_RELOC_AMD64_REL32;
  534. break;
  535. case 1:
  536. reloc->type = COFF_RELOC_AMD64_REL32_1;
  537. break;
  538. case 2:
  539. reloc->type = COFF_RELOC_AMD64_REL32_2;
  540. break;
  541. case 3:
  542. reloc->type = COFF_RELOC_AMD64_REL32_3;
  543. break;
  544. case 4:
  545. reloc->type = COFF_RELOC_AMD64_REL32_4;
  546. break;
  547. case 5:
  548. reloc->type = COFF_RELOC_AMD64_REL32_5;
  549. break;
  550. default:
  551. yasm_error_set(YASM_ERROR_TYPE,
  552. N_("coff: invalid relocation size"));
  553. return 1;
  554. }
  555. } else
  556. yasm_internal_error(N_("coff objfmt: unrecognized machine"));
  557. } else if (value->seg_of) {
  558. if (objfmt_coff->machine == COFF_MACHINE_I386)
  559. reloc->type = COFF_RELOC_I386_SECTION;
  560. else if (objfmt_coff->machine == COFF_MACHINE_AMD64)
  561. reloc->type = COFF_RELOC_AMD64_SECTION;
  562. else
  563. yasm_internal_error(N_("coff objfmt: unrecognized machine"));
  564. } else if (value->section_rel) {
  565. if (objfmt_coff->machine == COFF_MACHINE_I386)
  566. reloc->type = COFF_RELOC_I386_SECREL;
  567. else if (objfmt_coff->machine == COFF_MACHINE_AMD64)
  568. reloc->type = COFF_RELOC_AMD64_SECREL;
  569. else
  570. yasm_internal_error(N_("coff objfmt: unrecognized machine"));
  571. } else {
  572. if (objfmt_coff->machine == COFF_MACHINE_I386) {
  573. if (nobase)
  574. reloc->type = COFF_RELOC_I386_ADDR32NB;
  575. else
  576. reloc->type = COFF_RELOC_I386_ADDR32;
  577. } else if (objfmt_coff->machine == COFF_MACHINE_AMD64) {
  578. if (valsize == 32) {
  579. if (nobase)
  580. reloc->type = COFF_RELOC_AMD64_ADDR32NB;
  581. else
  582. reloc->type = COFF_RELOC_AMD64_ADDR32;
  583. } else if (valsize == 64)
  584. reloc->type = COFF_RELOC_AMD64_ADDR64;
  585. else {
  586. yasm_error_set(YASM_ERROR_TYPE,
  587. N_("coff: invalid relocation size"));
  588. return 1;
  589. }
  590. } else
  591. yasm_internal_error(N_("coff objfmt: unrecognized machine"));
  592. }
  593. info->csd->nreloc++;
  594. yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
  595. }
  596. /* Build up final integer output from intn_val, intn_minus, value->abs,
  597. * and dist. We do all this at the end to avoid creating temporary
  598. * intnums above (except for dist).
  599. */
  600. if (intn_minus <= intn_val)
  601. intn = yasm_intnum_create_uint(intn_val-intn_minus);
  602. else {
  603. intn = yasm_intnum_create_uint(intn_minus-intn_val);
  604. yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
  605. }
  606. if (value->abs) {
  607. yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
  608. if (!intn2) {
  609. yasm_error_set(YASM_ERROR_TOO_COMPLEX,
  610. N_("coff: relocation too complex"));
  611. yasm_intnum_destroy(intn);
  612. if (dist)
  613. yasm_intnum_destroy(dist);
  614. return 1;
  615. }
  616. yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
  617. }
  618. if (dist) {
  619. yasm_intnum_calc(intn, YASM_EXPR_ADD, dist);
  620. yasm_intnum_destroy(dist);
  621. }
  622. retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
  623. valsize, 0, bc, warn);
  624. yasm_intnum_destroy(intn);
  625. return retval;
  626. }
  627. static int
  628. coff_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
  629. {
  630. /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
  631. /*@null@*/ /*@only@*/ unsigned char *bigbuf;
  632. unsigned long size = REGULAR_OUTBUF_SIZE;
  633. int gap;
  634. assert(info != NULL);
  635. bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info,
  636. coff_objfmt_output_value, NULL);
  637. /* Don't bother doing anything else if size ended up being 0. */
  638. if (size == 0) {
  639. if (bigbuf)
  640. yasm_xfree(bigbuf);
  641. return 0;
  642. }
  643. info->csd->size += size;
  644. /* Warn that gaps are converted to 0 and write out the 0's. */
  645. if (gap) {
  646. unsigned long left;
  647. yasm_warn_set(YASM_WARN_UNINIT_CONTENTS,
  648. N_("uninitialized space declared in code/data section: zeroing"));
  649. /* Write out in chunks */
  650. memset(info->buf, 0, REGULAR_OUTBUF_SIZE);
  651. left = size;
  652. while (left > REGULAR_OUTBUF_SIZE) {
  653. fwrite(info->buf, REGULAR_OUTBUF_SIZE, 1, info->f);
  654. left -= REGULAR_OUTBUF_SIZE;
  655. }
  656. fwrite(info->buf, left, 1, info->f);
  657. } else {
  658. /* Output buf (or bigbuf if non-NULL) to file */
  659. fwrite(bigbuf ? bigbuf : info->buf, (size_t)size, 1, info->f);
  660. }
  661. /* If bigbuf was allocated, free it */
  662. if (bigbuf)
  663. yasm_xfree(bigbuf);
  664. return 0;
  665. }
  666. static int
  667. coff_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
  668. {
  669. /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
  670. /*@dependent@*/ /*@null@*/ coff_section_data *csd;
  671. long pos;
  672. coff_reloc *reloc;
  673. unsigned char *localbuf;
  674. assert(info != NULL);
  675. csd = yasm_section_get_data(sect, &coff_section_data_cb);
  676. assert(csd != NULL);
  677. /* Add to strtab if in win32 format and name > 8 chars */
  678. if (info->objfmt_coff->win32) {
  679. size_t namelen = strlen(yasm_section_get_name(sect));
  680. if (namelen > 8) {
  681. csd->strtab_name = info->strtab_offset;
  682. info->strtab_offset += (unsigned long)(namelen + 1);
  683. }
  684. }
  685. if (!csd->isdebug)
  686. csd->addr = info->addr;
  687. if ((csd->flags & COFF_STYP_STD_MASK) == COFF_STYP_BSS) {
  688. /* Don't output BSS sections.
  689. * TODO: Check for non-reserve bytecodes?
  690. */
  691. pos = 0; /* position = 0 because it's not in the file */
  692. csd->size = yasm_bc_next_offset(yasm_section_bcs_last(sect));
  693. } else {
  694. pos = ftell(info->f);
  695. if (pos == -1) {
  696. yasm__fatal(N_("could not get file position on output file"));
  697. /*@notreached@*/
  698. return 1;
  699. }
  700. info->sect = sect;
  701. info->csd = csd;
  702. yasm_section_bcs_traverse(sect, info->errwarns, info,
  703. coff_objfmt_output_bytecode);
  704. /* Sanity check final section size */
  705. if (yasm_errwarns_num_errors(info->errwarns, 0) == 0 &&
  706. csd->size != yasm_bc_next_offset(yasm_section_bcs_last(sect)))
  707. yasm_internal_error(
  708. N_("coff: section computed size did not match actual size"));
  709. }
  710. /* Empty? Go on to next section */
  711. if (csd->size == 0)
  712. return 0;
  713. if (!csd->isdebug)
  714. info->addr += csd->size;
  715. csd->scnptr = (unsigned long)pos;
  716. /* No relocations to output? Go on to next section */
  717. if (csd->nreloc == 0)
  718. return 0;
  719. pos = ftell(info->f);
  720. if (pos == -1) {
  721. yasm__fatal(N_("could not get file position on output file"));
  722. /*@notreached@*/
  723. return 1;
  724. }
  725. csd->relptr = (unsigned long)pos;
  726. /* If >=64K relocs (for Win32/64), we set a flag in the section header
  727. * (NRELOC_OVFL) and the first relocation contains the number of relocs.
  728. */
  729. if (csd->nreloc >= 64*1024 && info->objfmt_coff->win32) {
  730. localbuf = info->buf;
  731. YASM_WRITE_32_L(localbuf, csd->nreloc+1); /* address of relocation */
  732. YASM_WRITE_32_L(localbuf, 0); /* relocated symbol */
  733. YASM_WRITE_16_L(localbuf, 0); /* type of relocation */
  734. fwrite(info->buf, 10, 1, info->f);
  735. }
  736. reloc = (coff_reloc *)yasm_section_relocs_first(sect);
  737. while (reloc) {
  738. /*@null@*/ coff_symrec_data *csymd;
  739. localbuf = info->buf;
  740. csymd = yasm_symrec_get_data(reloc->reloc.sym, &coff_symrec_data_cb);
  741. if (!csymd)
  742. yasm_internal_error(
  743. N_("coff: no symbol data for relocated symbol"));
  744. yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0);
  745. localbuf += 4; /* address of relocation */
  746. YASM_WRITE_32_L(localbuf, csymd->index); /* relocated symbol */
  747. YASM_WRITE_16_L(localbuf, reloc->type); /* type of relocation */
  748. fwrite(info->buf, 10, 1, info->f);
  749. reloc = (coff_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc);
  750. }
  751. return 0;
  752. }
  753. static int
  754. coff_objfmt_output_sectstr(yasm_section *sect, /*@null@*/ void *d)
  755. {
  756. /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
  757. const char *name;
  758. size_t len;
  759. /* Add to strtab if in win32 format and name > 8 chars */
  760. if (!info->objfmt_coff->win32)
  761. return 0;
  762. name = yasm_section_get_name(sect);
  763. len = strlen(name);
  764. if (len > 8)
  765. fwrite(name, len+1, 1, info->f);
  766. return 0;
  767. }
  768. static int
  769. coff_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d)
  770. {
  771. /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
  772. yasm_objfmt_coff *objfmt_coff;
  773. /*@dependent@*/ /*@null@*/ coff_section_data *csd;
  774. unsigned char *localbuf;
  775. unsigned long align = yasm_section_get_align(sect);
  776. assert(info != NULL);
  777. objfmt_coff = info->objfmt_coff;
  778. csd = yasm_section_get_data(sect, &coff_section_data_cb);
  779. assert(csd != NULL);
  780. /* Check to see if alignment is supported size */
  781. if (align > 8192)
  782. align = 8192;
  783. /* Convert alignment into flags setting */
  784. csd->flags &= ~COFF_STYP_ALIGN_MASK;
  785. while (align != 0) {
  786. csd->flags += 1<<COFF_STYP_ALIGN_SHIFT;
  787. align >>= 1;
  788. }
  789. /* section name */
  790. localbuf = info->buf;
  791. if (strlen(yasm_section_get_name(sect)) > 8) {
  792. char namenum[30];
  793. sprintf(namenum, "/%ld", csd->strtab_name);
  794. strncpy((char *)localbuf, namenum, 8);
  795. } else
  796. strncpy((char *)localbuf, yasm_section_get_name(sect), 8);
  797. localbuf += 8;
  798. if (csd->isdebug) {
  799. YASM_WRITE_32_L(localbuf, 0); /* physical address */
  800. YASM_WRITE_32_L(localbuf, 0); /* virtual address */
  801. } else {
  802. YASM_WRITE_32_L(localbuf, csd->addr); /* physical address */
  803. if (COFF_SET_VMA)
  804. YASM_WRITE_32_L(localbuf, csd->addr);/* virtual address */
  805. else
  806. YASM_WRITE_32_L(localbuf, 0); /* virtual address */
  807. }
  808. YASM_WRITE_32_L(localbuf, csd->size); /* section size */
  809. YASM_WRITE_32_L(localbuf, csd->scnptr); /* file ptr to data */
  810. YASM_WRITE_32_L(localbuf, csd->relptr); /* file ptr to relocs */
  811. YASM_WRITE_32_L(localbuf, 0); /* file ptr to line nums */
  812. if (csd->nreloc >= 64*1024) {
  813. /* Win32/64 has special handling for this case. */
  814. if (objfmt_coff->win32)
  815. csd->flags |= COFF_STYP_NRELOC_OVFL;
  816. else {
  817. yasm_warn_set(YASM_WARN_GENERAL,
  818. N_("too many relocations in section `%s'"),
  819. yasm_section_get_name(sect));
  820. yasm_errwarn_propagate(info->errwarns, 0);
  821. }
  822. YASM_WRITE_16_L(localbuf, 0xFFFF); /* max out */
  823. } else
  824. YASM_WRITE_16_L(localbuf, csd->nreloc); /* num of relocation entries */
  825. YASM_WRITE_16_L(localbuf, 0); /* num of line number entries */
  826. YASM_WRITE_32_L(localbuf, csd->flags); /* flags */
  827. fwrite(info->buf, 40, 1, info->f);
  828. return 0;
  829. }
  830. static int
  831. coff_objfmt_count_sym(yasm_symrec *sym, /*@null@*/ void *d)
  832. {
  833. /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
  834. yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
  835. coff_symrec_data *sym_data;
  836. assert(info != NULL);
  837. sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
  838. if (info->all_syms || vis != YASM_SYM_LOCAL || yasm_symrec_is_abs(sym) ||
  839. (sym_data && sym_data->forcevis)) {
  840. /* Save index in symrec data */
  841. if (!sym_data)
  842. sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0,
  843. COFF_SYMTAB_AUX_NONE);
  844. /* Set storage class based on visibility if not already set */
  845. if (sym_data->sclass == COFF_SCL_NULL) {
  846. if (vis & (YASM_SYM_EXTERN|YASM_SYM_GLOBAL|YASM_SYM_COMMON))
  847. sym_data->sclass = COFF_SCL_EXT;
  848. else
  849. sym_data->sclass = COFF_SCL_STAT;
  850. }
  851. sym_data->index = info->indx;
  852. info->indx += sym_data->numaux + 1;
  853. }
  854. return 0;
  855. }
  856. static int
  857. coff_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d)
  858. {
  859. /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
  860. yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
  861. int is_abs = yasm_symrec_is_abs(sym);
  862. /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd;
  863. yasm_valparamhead *objext_valparams =
  864. yasm_symrec_get_objext_valparams(sym);
  865. csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
  866. assert(info != NULL);
  867. /* Look for "function" flag on global syms */
  868. if (csymd && csymd->type == 0 && (vis & YASM_SYM_GLOBAL) != 0) {
  869. if (objext_valparams) {
  870. const char *id = yasm_vp_id(yasm_vps_first(objext_valparams));
  871. if (yasm__strcasecmp(id, "function") == 0)
  872. csymd->type = 0x20;
  873. }
  874. }
  875. /* Don't output local syms unless outputting all syms */
  876. if (info->all_syms || vis != YASM_SYM_LOCAL || is_abs ||
  877. (csymd && csymd->forcevis)) {
  878. /*@only*/ char *name;
  879. const yasm_expr *equ_val;
  880. const yasm_intnum *intn;
  881. unsigned char *localbuf;
  882. size_t len;
  883. int aux;
  884. unsigned long value = 0;
  885. unsigned int scnum = 0xfffe; /* -2 = debugging symbol */
  886. /*@dependent@*/ /*@null@*/ yasm_section *sect;
  887. /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
  888. unsigned long scnlen = 0; /* for sect auxent */
  889. unsigned long nreloc = 0; /* for sect auxent */
  890. yasm_objfmt_coff *objfmt_coff = info->objfmt_coff;
  891. if (is_abs)
  892. name = yasm__xstrdup(".absolut");
  893. else
  894. name = yasm_symrec_get_global_name(sym, info->object);
  895. len = strlen(name);
  896. /* Get symrec's of_data (needed for storage class) */
  897. if (!csymd)
  898. yasm_internal_error(N_("coff: expected sym data to be present"));
  899. /* Look at symrec for value/scnum/etc. */
  900. if (yasm_symrec_get_label(sym, &precbc)) {
  901. if (precbc)
  902. sect = yasm_bc_get_section(precbc);
  903. else
  904. sect = NULL;
  905. /* it's a label: get value and offset.
  906. * If there is not a section, leave as debugging symbol.
  907. */
  908. if (sect) {
  909. /*@dependent@*/ /*@null@*/ coff_section_data *csectd;
  910. csectd = yasm_section_get_data(sect, &coff_section_data_cb);
  911. if (csectd) {
  912. scnum = csectd->scnum;
  913. scnlen = csectd->size;
  914. nreloc = csectd->nreloc;
  915. if (COFF_SET_VMA)
  916. value = csectd->addr;
  917. } else
  918. yasm_internal_error(N_("didn't understand section"));
  919. if (precbc)
  920. value += yasm_bc_next_offset(precbc);
  921. }
  922. } else if ((equ_val = yasm_symrec_get_equ(sym))) {
  923. yasm_expr *equ_val_copy = yasm_expr_copy(equ_val);
  924. intn = yasm_expr_get_intnum(&equ_val_copy, 1);
  925. if (!intn) {
  926. if (vis & YASM_SYM_GLOBAL) {
  927. yasm_error_set(YASM_ERROR_NOT_CONSTANT,
  928. N_("global EQU value not an integer expression"));
  929. yasm_errwarn_propagate(info->errwarns, equ_val->line);
  930. }
  931. } else
  932. value = yasm_intnum_get_uint(intn);
  933. yasm_expr_destroy(equ_val_copy);
  934. scnum = 0xffff; /* -1 = absolute symbol */
  935. } else {
  936. if (vis & YASM_SYM_COMMON) {
  937. /*@dependent@*/ /*@null@*/ yasm_expr **csize_expr;
  938. csize_expr = yasm_symrec_get_common_size(sym);
  939. assert(csize_expr != NULL);
  940. intn = yasm_expr_get_intnum(csize_expr, 1);
  941. if (!intn) {
  942. yasm_error_set(YASM_ERROR_NOT_CONSTANT,
  943. N_("COMMON data size not an integer expression"));
  944. yasm_errwarn_propagate(info->errwarns,
  945. (*csize_expr)->line);
  946. } else
  947. value = yasm_intnum_get_uint(intn);
  948. scnum = 0;
  949. }
  950. if (vis & YASM_SYM_EXTERN)
  951. scnum = 0;
  952. }
  953. localbuf = info->buf;
  954. if (len > 8) {
  955. YASM_WRITE_32_L(localbuf, 0); /* "zeros" field */
  956. YASM_WRITE_32_L(localbuf, info->strtab_offset); /* strtab offset */
  957. info->strtab_offset += (unsigned long)(len+1);
  958. } else {
  959. /* <8 chars, so no string table entry needed */
  960. strncpy((char *)localbuf, name, 8);
  961. localbuf += 8;
  962. }
  963. YASM_WRITE_32_L(localbuf, value); /* value */
  964. YASM_WRITE_16_L(localbuf, scnum); /* section number */
  965. YASM_WRITE_16_L(localbuf, csymd->type); /* type */
  966. YASM_WRITE_8(localbuf, csymd->sclass); /* storage class */
  967. YASM_WRITE_8(localbuf, csymd->numaux); /* number of aux entries */
  968. fwrite(info->buf, 18, 1, info->f);
  969. for (aux=0; aux<csymd->numaux; aux++) {
  970. localbuf = info->buf;
  971. memset(localbuf, 0, 18);
  972. switch (csymd->auxtype) {
  973. case COFF_SYMTAB_AUX_NONE:
  974. break;
  975. case COFF_SYMTAB_AUX_SECT:
  976. YASM_WRITE_32_L(localbuf, scnlen); /* section length */
  977. YASM_WRITE_16_L(localbuf, nreloc); /* number relocs */
  978. YASM_WRITE_16_L(localbuf, 0); /* number line nums */
  979. break;
  980. case COFF_SYMTAB_AUX_FILE:
  981. len = strlen(csymd->aux[0].fname);
  982. if (len > 14) {
  983. YASM_WRITE_32_L(localbuf, 0);
  984. YASM_WRITE_32_L(localbuf, info->strtab_offset);
  985. info->strtab_offset += (unsigned long)(len+1);
  986. } else
  987. strncpy((char *)localbuf, csymd->aux[0].fname, 14);
  988. break;
  989. default:
  990. yasm_internal_error(
  991. N_("coff: unrecognized aux symtab type"));
  992. }
  993. fwrite(info->buf, 18, 1, info->f);
  994. }
  995. yasm_xfree(name);
  996. }
  997. return 0;
  998. }
  999. static int
  1000. coff_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d)
  1001. {
  1002. /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
  1003. yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
  1004. /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd;
  1005. csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
  1006. assert(info != NULL);
  1007. /* Don't output local syms unless outputting all syms */
  1008. if (info->all_syms || vis != YASM_SYM_LOCAL ||
  1009. (csymd && csymd->forcevis)) {
  1010. /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object);
  1011. size_t len = strlen(name);
  1012. int aux;
  1013. if (!csymd)
  1014. yasm_internal_error(N_("coff: expected sym data to be present"));
  1015. if (len > 8)
  1016. fwrite(name, len+1, 1, info->f);
  1017. for (aux=0; aux<csymd->numaux; aux++) {
  1018. switch (csymd->auxtype) {
  1019. case COFF_SYMTAB_AUX_FILE:
  1020. len = strlen(csymd->aux[0].fname);
  1021. if (len > 14)
  1022. fwrite(csymd->aux[0].fname, len+1, 1, info->f);
  1023. break;
  1024. default:
  1025. break;
  1026. }
  1027. }
  1028. yasm_xfree(name);
  1029. }
  1030. return 0;
  1031. }
  1032. static void
  1033. coff_objfmt_output(yasm_object *object, FILE *f, int all_syms,
  1034. yasm_errwarns *errwarns)
  1035. {
  1036. yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
  1037. coff_objfmt_output_info info;
  1038. unsigned char *localbuf;
  1039. long pos;
  1040. unsigned long symtab_pos;
  1041. unsigned long symtab_count;
  1042. unsigned int flags;
  1043. unsigned long ts;
  1044. if (objfmt_coff->proc_frame) {
  1045. yasm_error_set_xref(objfmt_coff->proc_frame,
  1046. N_("procedure started here"));
  1047. yasm_error_set(YASM_ERROR_GENERAL,
  1048. N_("end of file in procedure frame"));
  1049. yasm_errwarn_propagate(errwarns, 0);
  1050. return;
  1051. }
  1052. if (objfmt_coff->filesym_data->aux[0].fname)
  1053. yasm_xfree(objfmt_coff->filesym_data->aux[0].fname);
  1054. if (!object->deb_filename) {
  1055. object->deb_filename = yasm_replace_path(
  1056. objfmt_coff->objfmt.module->replace_map, objfmt_coff->objfmt.module->replace_map_size,
  1057. object->src_filename, strlen(object->src_filename));
  1058. }
  1059. objfmt_coff->filesym_data->aux[0].fname =
  1060. yasm__xstrdup(object->deb_filename);
  1061. /* Force all syms for win64 because they're needed for relocations.
  1062. * FIXME: Not *all* syms need to be output, only the ones needed for
  1063. * relocation. Find a way to do that someday.
  1064. */
  1065. all_syms |= objfmt_coff->win64;
  1066. info.strtab_offset = 4;
  1067. info.object = object;
  1068. info.objfmt_coff = objfmt_coff;
  1069. info.errwarns = errwarns;
  1070. info.f = f;
  1071. info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
  1072. /* Allocate space for headers by seeking forward */
  1073. if (fseek(f, (long)(20+40*(objfmt_coff->parse_scnum-1)), SEEK_SET) < 0) {
  1074. yasm__fatal(N_("could not seek on output file"));
  1075. /*@notreached@*/
  1076. return;
  1077. }
  1078. /* Finalize symbol table (assign index to each symbol) */
  1079. info.indx = 0;
  1080. info.all_syms = all_syms;
  1081. yasm_symtab_traverse(object->symtab, &info, coff_objfmt_count_sym);
  1082. symtab_count = info.indx;
  1083. /* Section data/relocs */
  1084. if (COFF_SET_VMA) {
  1085. /* If we're setting the VMA, we need to do a first section pass to
  1086. * determine each section's addr value before actually outputting
  1087. * relocations, as a relocation's section address is added into the
  1088. * addends in the generated code.
  1089. */
  1090. info.addr = 0;
  1091. if (yasm_object_sections_traverse(object, &info,
  1092. coff_objfmt_set_section_addr))
  1093. return;
  1094. }
  1095. info.addr = 0;
  1096. if (yasm_object_sections_traverse(object, &info,
  1097. coff_objfmt_output_section))
  1098. return;
  1099. /* Symbol table */
  1100. pos = ftell(f);
  1101. if (pos == -1) {
  1102. yasm__fatal(N_("could not get file position on output file"));
  1103. /*@notreached@*/
  1104. return;
  1105. }
  1106. symtab_pos = (unsigned long)pos;
  1107. yasm_symtab_traverse(object->symtab, &info, coff_objfmt_output_sym);
  1108. /* String table */
  1109. yasm_fwrite_32_l(info.strtab_offset, f); /* total length */
  1110. yasm_object_sections_traverse(object, &info, coff_objfmt_output_sectstr);
  1111. yasm_symtab_traverse(object->symtab, &info, coff_objfmt_output_str);
  1112. /* Write headers */
  1113. if (fseek(f, 0, SEEK_SET) < 0) {
  1114. yasm__fatal(N_("could not seek on output file"));
  1115. /*@notreached@*/
  1116. return;
  1117. }
  1118. localbuf = info.buf;
  1119. YASM_WRITE_16_L(localbuf, objfmt_coff->machine); /* magic number */
  1120. YASM_WRITE_16_L(localbuf, objfmt_coff->parse_scnum-1);/* number of sects */
  1121. if (getenv("YASM_TEST_SUITE"))
  1122. ts = 0;
  1123. else
  1124. ts = (unsigned long)time(NULL);
  1125. YASM_WRITE_32_L(localbuf, ts); /* time/date stamp */
  1126. YASM_WRITE_32_L(localbuf, symtab_pos); /* file ptr to symtab */
  1127. YASM_WRITE_32_L(localbuf, symtab_count); /* number of symtabs */
  1128. YASM_WRITE_16_L(localbuf, 0); /* size of optional header (none) */
  1129. /* flags */
  1130. flags = 0;
  1131. if (strcmp(yasm_dbgfmt_keyword(object->dbgfmt), "null")==0)
  1132. flags = COFF_F_LNNO;
  1133. if (!all_syms)
  1134. flags |= COFF_F_LSYMS;
  1135. if (objfmt_coff->machine != COFF_MACHINE_AMD64)
  1136. flags |= COFF_F_AR32WR;
  1137. YASM_WRITE_16_L(localbuf, flags);
  1138. fwrite(info.buf, 20, 1, f);
  1139. yasm_object_sections_traverse(object, &info, coff_objfmt_output_secthead);
  1140. yasm_xfree(info.buf);
  1141. }
  1142. static void
  1143. coff_objfmt_destroy(yasm_objfmt *objfmt)
  1144. {
  1145. yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)objfmt;
  1146. if (objfmt_coff->filesym_data->aux[0].fname)
  1147. yasm_xfree(objfmt_coff->filesym_data->aux[0].fname);
  1148. if (objfmt_coff->unwind)
  1149. yasm_win64__uwinfo_destroy(objfmt_coff->unwind);
  1150. yasm_xfree(objfmt);
  1151. }
  1152. static yasm_section *
  1153. coff_objfmt_add_default_section(yasm_object *object)
  1154. {
  1155. yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
  1156. yasm_section *retval;
  1157. coff_section_data *csd;
  1158. int isnew;
  1159. retval = yasm_object_get_general(object, ".text", 16, 1, 0, &isnew, 0);
  1160. if (isnew) {
  1161. csd = yasm_section_get_data(retval, &coff_section_data_cb);
  1162. csd->flags = COFF_STYP_TEXT;
  1163. if (objfmt_coff->win32)
  1164. csd->flags |= COFF_STYP_EXECUTE | COFF_STYP_READ;
  1165. yasm_section_set_default(retval, 1);
  1166. }
  1167. return retval;
  1168. }
  1169. struct coff_section_switch_data {
  1170. int isdefault;
  1171. int gasflags;
  1172. unsigned long flags;
  1173. unsigned long flags2;
  1174. /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
  1175. };
  1176. /* GAS-style flags */
  1177. static int
  1178. coff_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d,
  1179. /*@unused@*/ uintptr_t arg)
  1180. {
  1181. struct coff_section_switch_data *data =
  1182. (struct coff_section_switch_data *)d;
  1183. int alloc = 0, load = 0, readonly = 0, code = 0, datasect = 0;
  1184. int shared = 0;
  1185. const char *s = yasm_vp_string(vp);
  1186. size_t i;
  1187. if (!s) {
  1188. yasm_error_set(YASM_ERROR_VALUE, N_("non-string section attribute"));
  1189. return -1;
  1190. }
  1191. /* For GAS, default to read/write data */
  1192. if (data->isdefault)
  1193. data->flags = COFF_STYP_TEXT | COFF_STYP_READ | COFF_STYP_WRITE;
  1194. for (i=0; i<strlen(s); i++) {
  1195. switch (s[i]) {
  1196. case 'a':
  1197. break;
  1198. case 'b':
  1199. alloc = 1;
  1200. load = 0;
  1201. break;
  1202. case 'n':
  1203. load = 0;
  1204. break;
  1205. case 's':
  1206. shared = 1;
  1207. /*@fallthrough@*/
  1208. case 'd':
  1209. datasect = 1;
  1210. load = 1;
  1211. readonly = 0;
  1212. break;
  1213. case 'x':
  1214. code = 1;
  1215. load = 1;
  1216. break;
  1217. case 'r':
  1218. datasect = 1;
  1219. load = 1;
  1220. readonly = 1;
  1221. break;
  1222. case 'w':
  1223. readonly = 0;
  1224. break;
  1225. default:
  1226. yasm_warn_set(YASM_WARN_GENERAL,
  1227. N_("unrecognized section attribute: `%c'"),
  1228. s[i]);
  1229. }
  1230. }
  1231. if (code)
  1232. data->flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
  1233. else if (datasect)
  1234. data->flags = COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE;
  1235. else if (readonly)
  1236. data->flags = COFF_STYP_DATA | COFF_STYP_READ;
  1237. else if (load)
  1238. data->flags = COFF_STYP_TEXT;
  1239. else if (alloc)
  1240. data->flags = COFF_STYP_BSS;
  1241. if (shared)
  1242. data->flags |= COFF_STYP_SHARED;
  1243. data->gasflags = 1;
  1244. return 0;
  1245. }
  1246. static /*@observer@*/ /*@null@*/ yasm_section *
  1247. coff_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
  1248. /*@unused@*/ /*@null@*/
  1249. yasm_valparamhead *objext_valparams,
  1250. unsigned long line)
  1251. {
  1252. yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
  1253. yasm_valparam *vp;
  1254. yasm_section *retval;
  1255. int isnew;
  1256. int iscode = 0;
  1257. int flags_override;
  1258. const char *sectname;
  1259. char *realname;
  1260. int resonly = 0;
  1261. unsigned long align = 0;
  1262. coff_section_data *csd;
  1263. struct coff_section_switch_data data;
  1264. static const yasm_dir_help help[] = {
  1265. { "code", 0, yasm_dir_helper_flag_set,
  1266. offsetof(struct coff_section_switch_data, flags),
  1267. COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ },
  1268. { "text", 0, yasm_dir_helper_flag_set,
  1269. offsetof(struct coff_section_switch_data, flags),
  1270. COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ },
  1271. { "data", 0, yasm_dir_helper_flag_set,
  1272. offsetof(struct coff_section_switch_data, flags),
  1273. COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE },
  1274. { "rdata", 0, yasm_dir_helper_flag_set,
  1275. offsetof(struct coff_section_switch_data, flags),
  1276. COFF_STYP_DATA | COFF_STYP_READ },
  1277. { "bss", 0, yasm_dir_helper_flag_set,
  1278. offsetof(struct coff_section_switch_data, flags),
  1279. COFF_STYP_BSS | COFF_STYP_READ | COFF_STYP_WRITE },
  1280. { "info", 0, yasm_dir_helper_flag_set,
  1281. offsetof(struct coff_section_switch_data, flags),
  1282. COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ },
  1283. { "gasflags", 1, coff_helper_gasflags, 0, 0 },
  1284. /* Win32 only below this point */
  1285. { "discard", 0, yasm_dir_helper_flag_or,
  1286. offsetof(struct coff_section_switch_data, flags), COFF_STYP_DISCARD},
  1287. { "nodiscard", 0, yasm_dir_helper_flag_and,
  1288. offsetof(struct coff_section_switch_data, flags), COFF_STYP_DISCARD},
  1289. { "cache", 0, yasm_dir_helper_flag_and,
  1290. offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOCACHE},
  1291. { "nocache", 0, yasm_dir_helper_flag_or,
  1292. offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOCACHE},
  1293. { "page", 0, yasm_dir_helper_flag_and,
  1294. offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOPAGE },
  1295. { "nopage", 0, yasm_dir_helper_flag_or,
  1296. offsetof(struct coff_section_switch_data, flags), COFF_STYP_NOPAGE },
  1297. { "share", 0, yasm_dir_helper_flag_or,
  1298. offsetof(struct coff_section_switch_data, flags), COFF_STYP_SHARED },
  1299. { "noshare", 0, yasm_dir_helper_flag_and,
  1300. offsetof(struct coff_section_switch_data, flags), COFF_STYP_SHARED },
  1301. { "execute", 0, yasm_dir_helper_flag_or,
  1302. offsetof(struct coff_section_switch_data, flags), COFF_STYP_EXECUTE},
  1303. { "noexecute", 0, yasm_dir_helper_flag_and,
  1304. offsetof(struct coff_section_switch_data, flags), COFF_STYP_EXECUTE},
  1305. { "read", 0, yasm_dir_helper_flag_or,
  1306. offsetof(struct coff_section_switch_data, flags), COFF_STYP_READ },
  1307. { "noread", 0, yasm_dir_helper_flag_and,
  1308. offsetof(struct coff_section_switch_data, flags), COFF_STYP_READ },
  1309. { "write", 0, yasm_dir_helper_flag_or,
  1310. offsetof(struct coff_section_switch_data, flags), COFF_STYP_WRITE },
  1311. { "nowrite", 0, yasm_dir_helper_flag_and,
  1312. offsetof(struct coff_section_switch_data, flags), COFF_STYP_WRITE },
  1313. { "base", 0, yasm_dir_helper_flag_and,
  1314. offsetof(struct coff_section_switch_data, flags2), COFF_FLAG_NOBASE},
  1315. { "nobase", 0, yasm_dir_helper_flag_or,
  1316. offsetof(struct coff_section_switch_data, flags2), COFF_FLAG_NOBASE},
  1317. { "align", 1, yasm_dir_helper_intn,
  1318. offsetof(struct coff_section_switch_data, align_intn), 0 }
  1319. };
  1320. vp = yasm_vps_first(valparams);
  1321. sectname = yasm_vp_string(vp);
  1322. if (!sectname)
  1323. return NULL;
  1324. vp = yasm_vps_next(vp);
  1325. data.isdefault = 0;
  1326. data.gasflags = 0;
  1327. data.flags = 0;
  1328. data.flags2 = 0;
  1329. data.align_intn = NULL;
  1330. if (strcmp(sectname, ".data") == 0) {
  1331. data.flags = COFF_STYP_DATA | COFF_STYP_READ | COFF_STYP_WRITE;
  1332. if (objfmt_coff->win32) {
  1333. if (objfmt_coff->machine == COFF_MACHINE_AMD64)
  1334. align = 16;
  1335. else
  1336. align = 4;
  1337. }
  1338. } else if (strcmp(sectname, ".bss") == 0) {
  1339. data.flags = COFF_STYP_BSS | COFF_STYP_READ | COFF_STYP_WRITE;
  1340. if (objfmt_coff->win32) {
  1341. if (objfmt_coff->machine == COFF_MACHINE_AMD64)
  1342. align = 16;
  1343. else
  1344. align = 4;
  1345. }
  1346. resonly = 1;
  1347. } else if (strcmp(sectname, ".text") == 0) {
  1348. data.flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
  1349. if (objfmt_coff->win32)
  1350. align = 16;
  1351. } else if (strcmp(sectname, ".rdata") == 0
  1352. || strncmp(sectname, ".rodata", 7) == 0
  1353. || strncmp(sectname, ".rdata$", 7) == 0) {
  1354. data.flags = COFF_STYP_DATA | COFF_STYP_READ;
  1355. if (objfmt_coff->win32)
  1356. align = 8;
  1357. else
  1358. yasm_warn_set(YASM_WARN_GENERAL,
  1359. N_("Standard COFF does not support read-only data sections"));
  1360. } else if (strcmp(sectname, ".drectve") == 0) {
  1361. data.flags = COFF_STYP_INFO;
  1362. if (objfmt_coff->win32)
  1363. data.flags |= COFF_STYP_DISCARD | COFF_STYP_READ;
  1364. } else if (objfmt_coff->win64 && strcmp(sectname, ".pdata") == 0) {
  1365. data.flags = COFF_STYP_DATA | COFF_STYP_READ;
  1366. align = 4;
  1367. data.flags2 = COFF_FLAG_NOBASE;
  1368. } else if (objfmt_coff->win64 && strcmp(sectname, ".xdata") == 0) {
  1369. data.flags = COFF_STYP_DATA | COFF_STYP_READ;
  1370. align = 8;
  1371. data.flags2 = COFF_FLAG_NOBASE;
  1372. } else if (objfmt_coff->win32 && strcmp(sectname, ".sxdata") == 0) {
  1373. data.flags = COFF_STYP_INFO;
  1374. } else if (strcmp(sectname, ".comment") == 0) {
  1375. data.flags = COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ;
  1376. } else if (yasm__strncasecmp(sectname, ".debug", 6)==0) {
  1377. data.flags = COFF_STYP_DATA | COFF_STYP_DISCARD | COFF_STYP_READ;
  1378. align = 1;
  1379. } else {
  1380. /* Default to code, but set a flag so if we get gasflags we can
  1381. * change it (NASM and GAS have different defaults).
  1382. */
  1383. data.isdefault = 1;
  1384. data.flags = COFF_STYP_TEXT | COFF_STYP_EXECUTE | COFF_STYP_READ;
  1385. }
  1386. flags_override = yasm_dir_helper(object, vp, line, help,
  1387. objfmt_coff->win32 ? NELEMS(help) : 7,
  1388. &data, yasm_dir_helper_valparam_warn);
  1389. if (flags_override < 0)
  1390. return NULL; /* error occurred */
  1391. if (data.flags & COFF_STYP_EXECUTE)
  1392. iscode = 1;
  1393. if (!objfmt_coff->win32)
  1394. data.flags &= ~COFF_STYP_WIN32_MASK;
  1395. if (data.align_intn) {
  1396. align = yasm_intnum_get_uint(data.align_intn);
  1397. yasm_intnum_destroy(data.align_intn);
  1398. /* Alignments must be a power of two. */
  1399. if (!is_exp2(align)) {
  1400. yasm_error_set(YASM_ERROR_VALUE,
  1401. N_("argument to `%s' is not a power of two"),
  1402. "align");
  1403. return NULL;
  1404. }
  1405. /* Check to see if alignment is supported size */
  1406. if (align > 8192) {
  1407. yasm_error_set(YASM_ERROR_VALUE,
  1408. N_("Win32 does not support alignments > 8192"));
  1409. return NULL;
  1410. }
  1411. }
  1412. realname = yasm__xstrdup(sectname);
  1413. if (strlen(sectname) > 8 && !objfmt_coff->win32) {
  1414. /* win32 format supports >8 character section names in object
  1415. * files via "/nnnn" (where nnnn is decimal offset into string table),
  1416. * so only warn for regular COFF.
  1417. */
  1418. yasm_warn_set(YASM_WARN_GENERAL,
  1419. N_("COFF section names limited to 8 characters: truncating"));
  1420. realname[8] = '\0';
  1421. }
  1422. retval = yasm_object_get_general(object, realname, align, iscode,
  1423. resonly, &isnew, line);
  1424. yasm_xfree(realname);
  1425. csd = yasm_section_get_data(retval, &coff_section_data_cb);
  1426. if (isnew || yasm_section_is_default(retval)) {
  1427. yasm_section_set_default(retval, 0);
  1428. csd->flags = data.flags;
  1429. csd->flags2 = data.flags2;
  1430. yasm_section_set_align(retval, align, line);
  1431. } else if (flags_override && !data.gasflags)
  1432. yasm_warn_set(YASM_WARN_GENERAL,
  1433. N_("section flags ignored on section redeclaration"));
  1434. return retval;
  1435. }
  1436. static /*@observer@*/ /*@null@*/ yasm_symrec *
  1437. coff_objfmt_get_special_sym(yasm_object *object, const char *name,
  1438. const char *parser)
  1439. {
  1440. return NULL;
  1441. }
  1442. static /*@observer@*/ /*@null@*/ yasm_symrec *
  1443. win64_objfmt_get_special_sym(yasm_object *object, const char *name,
  1444. const char *parser)
  1445. {
  1446. if (yasm__strcasecmp(name, "imagebase") == 0) {
  1447. yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
  1448. return objfmt_coff->ssym_imagebase;
  1449. }
  1450. return NULL;
  1451. }
  1452. static void
  1453. coff_section_data_destroy(void *data)
  1454. {
  1455. yasm_xfree(data);
  1456. }
  1457. static void
  1458. coff_section_data_print(void *data, FILE *f, int indent_level)
  1459. {
  1460. coff_section_data *csd = (coff_section_data *)data;
  1461. fprintf(f, "%*ssym=\n", indent_level, "");
  1462. yasm_symrec_print(csd->sym, f, indent_level+1);
  1463. fprintf(f, "%*sscnum=%d\n", indent_level, "", csd->scnum);
  1464. fprintf(f, "%*sflags=", indent_level, "");
  1465. switch (csd->flags & COFF_STYP_STD_MASK) {
  1466. case COFF_STYP_TEXT:
  1467. fprintf(f, "TEXT");
  1468. break;
  1469. case COFF_STYP_DATA:
  1470. fprintf(f, "DATA");
  1471. break;
  1472. case COFF_STYP_BSS:
  1473. fprintf(f, "BSS");
  1474. break;
  1475. default:
  1476. fprintf(f, "UNKNOWN");
  1477. break;
  1478. }
  1479. fprintf(f, "\n%*saddr=0x%lx\n", indent_level, "", csd->addr);
  1480. fprintf(f, "%*sscnptr=0x%lx\n", indent_level, "", csd->scnptr);
  1481. fprintf(f, "%*ssize=%ld\n", indent_level, "", csd->size);
  1482. fprintf(f, "%*srelptr=0x%lx\n", indent_level, "", csd->relptr);
  1483. fprintf(f, "%*snreloc=%ld\n", indent_level, "", csd->nreloc);
  1484. fprintf(f, "%*srelocs:\n", indent_level, "");
  1485. }
  1486. static void
  1487. coff_symrec_data_destroy(void *data)
  1488. {
  1489. yasm_xfree(data);
  1490. }
  1491. static void
  1492. coff_symrec_data_print(void *data, FILE *f, int indent_level)
  1493. {
  1494. coff_symrec_data *csd = (coff_symrec_data *)data;
  1495. fprintf(f, "%*ssymtab index=%lu\n", indent_level, "", csd->index);
  1496. fprintf(f, "%*ssclass=%d\n", indent_level, "", csd->sclass);
  1497. }
  1498. static void
  1499. dir_export(yasm_object *object, yasm_valparamhead *valparams,
  1500. yasm_valparamhead *objext_valparams, unsigned long line)
  1501. {
  1502. yasm_valparam *vp;
  1503. /*@null@*/ const char *symname;
  1504. int isnew;
  1505. yasm_section *sect;
  1506. yasm_datavalhead dvs;
  1507. /* Reference exported symbol (to generate error if not declared) */
  1508. vp = yasm_vps_first(valparams);
  1509. symname = yasm_vp_id(vp);
  1510. if (symname)
  1511. yasm_symtab_use(object->symtab, symname, line);
  1512. else {
  1513. yasm_error_set(YASM_ERROR_SYNTAX,
  1514. N_("argument to EXPORT must be symbol name"));
  1515. return;
  1516. }
  1517. /* Add to end of linker directives */
  1518. sect = yasm_object_get_general(object, ".drectve", 0, 0, 0, &isnew, line);
  1519. /* Initialize directive section if needed */
  1520. if (isnew) {
  1521. coff_section_data *csd;
  1522. csd = yasm_section_get_data(sect, &coff_section_data_cb);
  1523. csd->flags = COFF_STYP_INFO | COFF_STYP_DISCARD | COFF_STYP_READ;
  1524. }
  1525. /* Add text as data bytecode */
  1526. yasm_dvs_initialize(&dvs);
  1527. yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup("-export:"),
  1528. strlen("-export:")));
  1529. yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(symname),
  1530. strlen(symname)));
  1531. yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(" "), 1));
  1532. yasm_section_bcs_append(sect, yasm_bc_create_data(&dvs, 1, 0, NULL, line));
  1533. }
  1534. static void
  1535. dir_safeseh(yasm_object *object, yasm_valparamhead *valparams,
  1536. yasm_valparamhead *objext_valparams, unsigned long line)
  1537. {
  1538. yasm_valparam *vp;
  1539. /*@null@*/ const char *symname;
  1540. yasm_symrec *sym;
  1541. int isnew;
  1542. yasm_section *sect;
  1543. /* Reference symbol (to generate error if not declared).
  1544. * Also, symbol must be externally visible, so force it.
  1545. */
  1546. vp = yasm_vps_first(valparams);
  1547. symname = yasm_vp_id(vp);
  1548. if (symname) {
  1549. coff_symrec_data *sym_data;
  1550. sym = yasm_symtab_use(object->symtab, symname, line);
  1551. sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
  1552. if (!sym_data) {
  1553. sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0,
  1554. COFF_SYMTAB_AUX_NONE);
  1555. }
  1556. sym_data->forcevis = 1;
  1557. sym_data->type = 0x20; /* function */
  1558. } else {
  1559. yasm_error_set(YASM_ERROR_SYNTAX,
  1560. N_("argument to SAFESEH must be symbol name"));
  1561. return;
  1562. }
  1563. /*
  1564. * Add symbol number to end of .sxdata section.
  1565. */
  1566. sect = yasm_object_get_general(object, ".sxdata", 0, 0, 0, &isnew, line);
  1567. /* Initialize sxdata section if needed */
  1568. if (isnew) {
  1569. coff_section_data *csd;
  1570. csd = yasm_section_get_data(sect, &coff_section_data_cb);
  1571. csd->flags = COFF_STYP_INFO;
  1572. }
  1573. /* Add as sxdata bytecode */
  1574. yasm_section_bcs_append(sect,
  1575. yasm_bc_create_common(&win32_sxdata_bc_callback,
  1576. sym, line));
  1577. }
  1578. static void
  1579. win32_sxdata_bc_destroy(void *contents)
  1580. {
  1581. /* Contents is just the symbol pointer, so no need to delete */
  1582. }
  1583. static void
  1584. win32_sxdata_bc_print(const void *contents, FILE *f, int indent_level)
  1585. {
  1586. /* TODO */
  1587. }
  1588. static int
  1589. win32_sxdata_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
  1590. void *add_span_data)
  1591. {
  1592. bc->len += 4;
  1593. return 0;
  1594. }
  1595. static int
  1596. win32_sxdata_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp,
  1597. unsigned char *bufstart, void *d,
  1598. yasm_output_value_func output_value,
  1599. yasm_output_reloc_func output_reloc)
  1600. {
  1601. yasm_symrec *sym = (yasm_symrec *)bc->contents;
  1602. unsigned char *buf = *bufp;
  1603. coff_symrec_data *csymd;
  1604. csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
  1605. if (!csymd)
  1606. yasm_internal_error(N_("coff: no symbol data for SAFESEH symbol"));
  1607. YASM_WRITE_32_L(buf, csymd->index);
  1608. *bufp = buf;
  1609. return 0;
  1610. }
  1611. static void
  1612. dir_ident(yasm_object *object, yasm_valparamhead *valparams,
  1613. yasm_valparamhead *objext_valparams, unsigned long line)
  1614. {
  1615. yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
  1616. yasm_valparamhead sect_vps;
  1617. yasm_datavalhead dvs;
  1618. yasm_section *comment;
  1619. const char *sectname;
  1620. yasm_valparam *vp, *vp2;
  1621. /* Accept, but do nothing with empty ident */
  1622. if (!valparams)
  1623. return;
  1624. vp = yasm_vps_first(valparams);
  1625. if (!vp)
  1626. return;
  1627. if (objfmt_coff->win32) {
  1628. /* Put ident data into .comment section for COFF, or .rdata$zzz
  1629. * to be compatible with the GNU linker, which doesn't ignore
  1630. * .comment (see binutils/gas/config/obj-coff.c:476-502).
  1631. */
  1632. sectname = ".rdata$zzz";
  1633. } else {
  1634. sectname = ".comment";
  1635. }
  1636. yasm_vps_initialize(&sect_vps);
  1637. vp2 = yasm_vp_create_id(NULL, yasm__xstrdup(sectname), '\0');
  1638. yasm_vps_append(&sect_vps, vp2);
  1639. comment = coff_objfmt_section_switch(object, &sect_vps, NULL, line);
  1640. yasm_vps_delete(&sect_vps);
  1641. /* To match GAS output, if the comment section is empty, put an
  1642. * initial 0 byte in the section.
  1643. */
  1644. if (yasm_section_bcs_first(comment) == yasm_section_bcs_last(comment)) {
  1645. yasm_dvs_initialize(&dvs);
  1646. yasm_dvs_append(&dvs, yasm_dv_create_expr(
  1647. yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)),
  1648. line)));
  1649. yasm_section_bcs_append(comment,
  1650. yasm_bc_create_data(&dvs, 1, 0, object->arch, line));
  1651. }
  1652. yasm_dvs_initialize(&dvs);
  1653. do {
  1654. const char *s = yasm_vp_string(vp);
  1655. if (!s) {
  1656. yasm_error_set(YASM_ERROR_VALUE,
  1657. N_(".comment requires string parameters"));
  1658. yasm_dvs_delete(&dvs);
  1659. return;
  1660. }
  1661. yasm_dvs_append(&dvs,
  1662. yasm_dv_create_string(yasm__xstrdup(s), strlen(s)));
  1663. } while ((vp = yasm_vps_next(vp)));
  1664. yasm_section_bcs_append(comment,
  1665. yasm_bc_create_data(&dvs, 1, 1, object->arch, line));
  1666. }
  1667. static void
  1668. dir_secrel32(yasm_object *object, yasm_valparamhead *valparams,
  1669. yasm_valparamhead *objext_valparams, unsigned long line)
  1670. {
  1671. yasm_datavalhead dvs;
  1672. yasm_valparam *vp;
  1673. if (!object->cur_section) {
  1674. yasm_error_set(YASM_ERROR_SYNTAX,
  1675. N_(".secrel32 can only be used inside of a section"));
  1676. return;
  1677. }
  1678. vp = yasm_vps_first(valparams);
  1679. yasm_dvs_initialize(&dvs);
  1680. do {
  1681. yasm_expr *e = yasm_vp_expr(vp, object->symtab, line);
  1682. yasm_dataval *dv;
  1683. if (!e) {
  1684. yasm_error_set(YASM_ERROR_VALUE,
  1685. N_(".secrel32 requires expressions"));
  1686. yasm_dvs_delete(&dvs);
  1687. return;
  1688. }
  1689. dv = yasm_dv_create_expr(e);
  1690. yasm_dv_get_value(dv)->section_rel = 1;
  1691. yasm_dvs_append(&dvs, dv);
  1692. } while ((vp = yasm_vps_next(vp)));
  1693. yasm_section_bcs_append(object->cur_section,
  1694. yasm_bc_create_data(&dvs, 4, 0, object->arch, line));
  1695. }
  1696. static void
  1697. dir_def(yasm_object *object, yasm_valparamhead *valparams,
  1698. yasm_valparamhead *objext_valparams, unsigned long line)
  1699. {
  1700. yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
  1701. yasm_valparam *vp;
  1702. const char *symname;
  1703. yasm_symrec *sym;
  1704. coff_symrec_data *sym_data;
  1705. if (objfmt_coff->def_sym) {
  1706. yasm_warn_set(YASM_WARN_GENERAL,
  1707. N_(".def pseudo-op used inside of .def/.endef; ignored"));
  1708. return;
  1709. }
  1710. vp = yasm_vps_first(valparams);
  1711. symname = yasm_vp_id(vp);
  1712. if (!symname) {
  1713. yasm_error_set(YASM_ERROR_SYNTAX,
  1714. N_("argument to SAFESEH must be symbol name"));
  1715. return;
  1716. }
  1717. sym = yasm_symtab_use(object->symtab, symname, line);
  1718. sym_data = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
  1719. if (!sym_data) {
  1720. sym_data = coff_objfmt_sym_set_data(sym, COFF_SCL_NULL, 0,
  1721. COFF_SYMTAB_AUX_NONE);
  1722. }
  1723. objfmt_coff->def_sym = sym_data;
  1724. }
  1725. static void
  1726. dir_scl(yasm_object *object, yasm_valparamhead *valparams,
  1727. yasm_valparamhead *objext_valparams, unsigned long line)
  1728. {
  1729. yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
  1730. yasm_intnum *intn = NULL;
  1731. if (!objfmt_coff->def_sym) {
  1732. yasm_warn_set(YASM_WARN_GENERAL,
  1733. N_("%s pseudo-op used outside of .def/.endef; ignored"),
  1734. ".scl");
  1735. return;
  1736. }
  1737. if (yasm_dir_helper_intn(object, yasm_vps_first(valparams), line,
  1738. &intn, 0) < 0)
  1739. return;
  1740. if (!intn)
  1741. return;
  1742. objfmt_coff->def_sym->sclass = yasm_intnum_get_uint(intn);
  1743. yasm_intnum_destroy(intn);
  1744. }
  1745. static void
  1746. dir_type(yasm_object *object, yasm_valparamhead *valparams,
  1747. yasm_valparamhead *objext_valparams, unsigned long line)
  1748. {
  1749. yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
  1750. yasm_intnum *intn = NULL;
  1751. if (!objfmt_coff->def_sym) {
  1752. yasm_warn_set(YASM_WARN_GENERAL,
  1753. N_("%s pseudo-op used outside of .def/.endef; ignored"),
  1754. ".type");
  1755. return;
  1756. }
  1757. if (yasm_dir_helper_intn(object, yasm_vps_first(valparams), line,
  1758. &intn, 0) < 0)
  1759. return;
  1760. if (!intn)
  1761. return;
  1762. objfmt_coff->def_sym->type = yasm_intnum_get_uint(intn);
  1763. yasm_intnum_destroy(intn);
  1764. }
  1765. static void
  1766. dir_endef(yasm_object *object, yasm_valparamhead *valparams,
  1767. yasm_valparamhead *objext_valparams, unsigned long line)
  1768. {
  1769. yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
  1770. if (!objfmt_coff->def_sym) {
  1771. yasm_warn_set(YASM_WARN_GENERAL,
  1772. N_(".endef pseudo-op used before .def; ignored"));
  1773. return;
  1774. }
  1775. objfmt_coff->def_sym = NULL;
  1776. }
  1777. static void
  1778. dir_proc_frame(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
  1779. yasm_valparamhead *objext_valparams, unsigned long line)
  1780. {
  1781. yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
  1782. yasm_valparam *vp = yasm_vps_first(valparams);
  1783. const char *name = yasm_vp_id(vp);
  1784. if (objfmt_coff->proc_frame) {
  1785. yasm_error_set_xref(objfmt_coff->proc_frame,
  1786. N_("previous procedure started here"));
  1787. yasm_error_set(YASM_ERROR_SYNTAX,
  1788. N_("nested procedures not supported (didn't use [ENDPROC_FRAME]?)"));
  1789. return;
  1790. }
  1791. objfmt_coff->proc_frame = line;
  1792. objfmt_coff->done_prolog = 0;
  1793. objfmt_coff->unwind = yasm_win64__uwinfo_create();
  1794. objfmt_coff->unwind->proc = yasm_symtab_use(object->symtab, name, line);
  1795. /* Optional error handler */
  1796. vp = yasm_vps_next(vp);
  1797. if (!vp || !(name = yasm_vp_id(vp)))
  1798. return;
  1799. objfmt_coff->unwind->ehandler =
  1800. yasm_symtab_use(object->symtab, name, line);
  1801. }
  1802. static int
  1803. procframe_checkstate(yasm_objfmt_coff *objfmt_coff, const char *dirname)
  1804. {
  1805. if (!objfmt_coff->proc_frame) {
  1806. yasm_error_set(YASM_ERROR_SYNTAX,
  1807. N_("[%s] without preceding [PROC_FRAME]"), dirname);
  1808. return 0;
  1809. }
  1810. if (objfmt_coff->done_prolog) {
  1811. yasm_error_set_xref(objfmt_coff->done_prolog,
  1812. N_("prologue ended here"));
  1813. yasm_error_set(YASM_ERROR_SYNTAX, N_("[%s] after end of prologue"),
  1814. dirname);
  1815. return 0;
  1816. }
  1817. if (!objfmt_coff->unwind)
  1818. yasm_internal_error(N_("unwind info not present"));
  1819. return 1;
  1820. }
  1821. /* Get current assembly position.
  1822. * XXX: There should be a better way to do this.
  1823. */
  1824. static yasm_symrec *
  1825. get_curpos(yasm_object *object, const char *dirname, unsigned long line)
  1826. {
  1827. if (!object->cur_section) {
  1828. yasm_error_set(YASM_ERROR_SYNTAX,
  1829. N_("[%s] can only be used inside of a section"),
  1830. dirname);
  1831. return NULL;
  1832. }
  1833. return yasm_symtab_define_curpos(object->symtab, "$",
  1834. yasm_section_bcs_last(object->cur_section), line);
  1835. }
  1836. static void
  1837. dir_pushreg(yasm_object *object, yasm_valparamhead *valparams,
  1838. yasm_valparamhead *objext_valparams, unsigned long line)
  1839. {
  1840. yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
  1841. yasm_valparam *vp = yasm_vps_first(valparams);
  1842. coff_unwind_code *code;
  1843. const uintptr_t *reg;
  1844. if (!procframe_checkstate(objfmt_coff, "PUSHREG"))
  1845. return;
  1846. if (vp->type != YASM_PARAM_EXPR ||
  1847. !(reg = yasm_expr_get_reg(&vp->param.e, 0))) {
  1848. yasm_error_set(YASM_ERROR_SYNTAX,
  1849. N_("[%s] requires a register as the first parameter"),
  1850. "PUSHREG");
  1851. return;
  1852. }
  1853. /* Generate a PUSH_NONVOL unwind code. */
  1854. code = yasm_xmalloc(sizeof(coff_unwind_code));
  1855. code->proc = objfmt_coff->unwind->proc;
  1856. code->loc = get_curpos(object, "PUSHREG", line);
  1857. code->opcode = UWOP_PUSH_NONVOL;
  1858. code->info = (unsigned int)(*reg & 0xF);
  1859. yasm_value_initialize(&code->off, NULL, 0);
  1860. SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
  1861. }
  1862. static void
  1863. dir_setframe(yasm_object *object, yasm_valparamhead *valparams,
  1864. yasm_valparamhead *objext_valparams, unsigned long line)
  1865. {
  1866. yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
  1867. yasm_valparam *vp = yasm_vps_first(valparams);
  1868. coff_unwind_code *code;
  1869. const uintptr_t *reg;
  1870. yasm_expr *off = NULL;
  1871. if (!procframe_checkstate(objfmt_coff, "SETFRAME"))
  1872. return;
  1873. if (vp->type != YASM_PARAM_EXPR ||
  1874. !(reg = yasm_expr_get_reg(&vp->param.e, 0))) {
  1875. yasm_error_set(YASM_ERROR_SYNTAX,
  1876. N_("[%s] requires a register as the first parameter"),
  1877. "SETFRAME");
  1878. return;
  1879. }
  1880. vp = yasm_vps_next(vp);
  1881. if (vp)
  1882. off = yasm_vp_expr(vp, object->symtab, line);
  1883. /* Set the frame fields in the unwind info */
  1884. objfmt_coff->unwind->framereg = (unsigned long)(*reg);
  1885. yasm_value_initialize(&objfmt_coff->unwind->frameoff, off, 8);
  1886. /* Generate a SET_FPREG unwind code */
  1887. code = yasm_xmalloc(sizeof(coff_unwind_code));
  1888. code->proc = objfmt_coff->unwind->proc;
  1889. code->loc = get_curpos(object, "SETFRAME", line);
  1890. code->opcode = UWOP_SET_FPREG;
  1891. code->info = (unsigned int)(*reg & 0xF);
  1892. yasm_value_initialize(&code->off, off ? yasm_expr_copy(off) : NULL, 8);
  1893. SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
  1894. }
  1895. static void
  1896. dir_allocstack(yasm_object *object, yasm_valparamhead *valparams,
  1897. yasm_valparamhead *objext_valparams, unsigned long line)
  1898. {
  1899. yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
  1900. yasm_valparam *vp = yasm_vps_first(valparams);
  1901. /*@null@*/ /*@only@*/ yasm_expr *size;
  1902. coff_unwind_code *code;
  1903. if (!procframe_checkstate(objfmt_coff, "ALLOCSTACK"))
  1904. return;
  1905. size = yasm_vp_expr(vp, object->symtab, line);
  1906. if (!size) {
  1907. yasm_error_set(YASM_ERROR_SYNTAX, N_("[%s] requires a size"),
  1908. "ALLOCSTACK");
  1909. return;
  1910. }
  1911. /* Generate an ALLOC_SMALL unwind code; this will get enlarged to an
  1912. * ALLOC_LARGE if necessary.
  1913. */
  1914. code = yasm_xmalloc(sizeof(coff_unwind_code));
  1915. code->proc = objfmt_coff->unwind->proc;
  1916. code->loc = get_curpos(object, "ALLOCSTACK", line);
  1917. code->opcode = UWOP_ALLOC_SMALL;
  1918. code->info = 0;
  1919. yasm_value_initialize(&code->off, size, 7);
  1920. SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
  1921. }
  1922. static void
  1923. dir_save_common(yasm_object *object, yasm_valparamhead *valparams,
  1924. unsigned long line, const char *name, int op)
  1925. {
  1926. yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
  1927. yasm_valparam *vp = yasm_vps_first(valparams);
  1928. coff_unwind_code *code;
  1929. const uintptr_t *reg;
  1930. /*@only@*/ /*@null@*/ yasm_expr *offset;
  1931. if (!procframe_checkstate(objfmt_coff, name))
  1932. return;
  1933. if (vp->type != YASM_PARAM_EXPR ||
  1934. !(reg = yasm_expr_get_reg(&vp->param.e, 0))) {
  1935. yasm_error_set(YASM_ERROR_SYNTAX,
  1936. N_("[%s] requires a register as the first parameter"),
  1937. name);
  1938. return;
  1939. }
  1940. vp = yasm_vps_next(vp);
  1941. offset = yasm_vp_expr(vp, object->symtab, line);
  1942. if (!offset) {
  1943. yasm_error_set(YASM_ERROR_SYNTAX,
  1944. N_("[%s] requires an offset as the second parameter"),
  1945. name);
  1946. return;
  1947. }
  1948. /* Generate a SAVE_XXX unwind code; this will get enlarged to a
  1949. * SAVE_XXX_FAR if necessary.
  1950. */
  1951. code = yasm_xmalloc(sizeof(coff_unwind_code));
  1952. code->proc = objfmt_coff->unwind->proc;
  1953. code->loc = get_curpos(object, name, line);
  1954. code->opcode = op;
  1955. code->info = (unsigned int)(*reg & 0xF);
  1956. yasm_value_initialize(&code->off, offset, 16);
  1957. SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
  1958. }
  1959. static void
  1960. dir_savereg(yasm_object *object, yasm_valparamhead *valparams,
  1961. yasm_valparamhead *objext_valparams, unsigned long line)
  1962. {
  1963. dir_save_common(object, valparams, line, "SAVEREG", UWOP_SAVE_NONVOL);
  1964. }
  1965. static void
  1966. dir_savexmm128(yasm_object *object, yasm_valparamhead *valparams,
  1967. yasm_valparamhead *objext_valparams, unsigned long line)
  1968. {
  1969. dir_save_common(object, valparams, line, "SAVEXMM128", UWOP_SAVE_XMM128);
  1970. }
  1971. static void
  1972. dir_pushframe(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
  1973. yasm_valparamhead *objext_valparams, unsigned long line)
  1974. {
  1975. yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
  1976. yasm_valparam *vp = yasm_vps_first(valparams);
  1977. coff_unwind_code *code;
  1978. if (!procframe_checkstate(objfmt_coff, "PUSHFRAME"))
  1979. return;
  1980. /* Generate a PUSH_MACHFRAME unwind code. If there's any parameter,
  1981. * we set info to 1. Otherwise we set info to 0.
  1982. */
  1983. code = yasm_xmalloc(sizeof(coff_unwind_code));
  1984. code->proc = objfmt_coff->unwind->proc;
  1985. code->loc = get_curpos(object, "PUSHFRAME", line);
  1986. code->opcode = UWOP_PUSH_MACHFRAME;
  1987. code->info = vp != NULL;
  1988. yasm_value_initialize(&code->off, NULL, 0);
  1989. SLIST_INSERT_HEAD(&objfmt_coff->unwind->codes, code, link);
  1990. }
  1991. static void
  1992. dir_endprolog(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
  1993. yasm_valparamhead *objext_valparams, unsigned long line)
  1994. {
  1995. yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
  1996. if (!procframe_checkstate(objfmt_coff, "ENDPROLOG"))
  1997. return;
  1998. objfmt_coff->done_prolog = line;
  1999. objfmt_coff->unwind->prolog = get_curpos(object, "ENDPROLOG", line);
  2000. }
  2001. static void
  2002. dir_endproc_frame(yasm_object *object, /*@null@*/ yasm_valparamhead *valparams,
  2003. yasm_valparamhead *objext_valparams, unsigned long line)
  2004. {
  2005. yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)object->objfmt;
  2006. yasm_section *sect;
  2007. coff_section_data *csd;
  2008. yasm_datavalhead dvs;
  2009. int isnew;
  2010. /*@dependent@*/ yasm_symrec *curpos, *unwindpos, *proc_sym, *xdata_sym;
  2011. if (!objfmt_coff->proc_frame) {
  2012. yasm_error_set(YASM_ERROR_SYNTAX,
  2013. N_("[%s] without preceding [PROC_FRAME]"),
  2014. "ENDPROC_FRAME");
  2015. return;
  2016. }
  2017. if (!objfmt_coff->done_prolog) {
  2018. yasm_error_set_xref(objfmt_coff->proc_frame,
  2019. N_("procedure started here"));
  2020. yasm_error_set(YASM_ERROR_SYNTAX,
  2021. N_("ended procedure without ending prologue"),
  2022. "ENDPROC_FRAME");
  2023. objfmt_coff->proc_frame = 0;
  2024. yasm_win64__uwinfo_destroy(objfmt_coff->unwind);
  2025. objfmt_coff->unwind = NULL;
  2026. return;
  2027. }
  2028. if (!objfmt_coff->unwind)
  2029. yasm_internal_error(N_("unwind info not present"));
  2030. proc_sym = objfmt_coff->unwind->proc;
  2031. curpos = get_curpos(object, "ENDPROC_FRAME", line);
  2032. /*
  2033. * Add unwind info to end of .xdata section.
  2034. */
  2035. sect = yasm_object_get_general(object, ".xdata", 0, 0, 0, &isnew, line);
  2036. /* Initialize xdata section if needed */
  2037. if (isnew) {
  2038. csd = yasm_section_get_data(sect, &coff_section_data_cb);
  2039. csd->flags = COFF_STYP_DATA | COFF_STYP_READ;
  2040. yasm_section_set_align(sect, 8, line);
  2041. }
  2042. /* Get current position in .xdata section */
  2043. unwindpos = yasm_symtab_define_curpos(object->symtab, "$",
  2044. yasm_section_bcs_last(sect), line);
  2045. /* Get symbol for .xdata as we'll want to reference it with WRT */
  2046. csd = yasm_section_get_data(sect, &coff_section_data_cb);
  2047. xdata_sym = csd->sym;
  2048. /* Add unwind info. Use line number of start of procedure. */
  2049. yasm_win64__unwind_generate(sect, objfmt_coff->unwind,
  2050. objfmt_coff->proc_frame);
  2051. objfmt_coff->unwind = NULL; /* generate keeps the unwind pointer */
  2052. /*
  2053. * Add function lookup to end of .pdata section.
  2054. */
  2055. sect = yasm_object_get_general(object, ".pdata", 0, 0, 0, &isnew, line);
  2056. /* Initialize pdata section if needed */
  2057. if (isnew) {
  2058. csd = yasm_section_get_data(sect, &coff_section_data_cb);
  2059. csd->flags = COFF_STYP_DATA | COFF_STYP_READ;
  2060. csd->flags2 = COFF_FLAG_NOBASE;
  2061. yasm_section_set_align(sect, 4, line);
  2062. }
  2063. /* Add function structure as data bytecode */
  2064. yasm_dvs_initialize(&dvs);
  2065. yasm_dvs_append(&dvs, yasm_dv_create_expr(
  2066. yasm_expr_create_ident(yasm_expr_sym(proc_sym), line)));
  2067. yasm_dvs_append(&dvs, yasm_dv_create_expr(
  2068. yasm_expr_create(YASM_EXPR_WRT, yasm_expr_sym(curpos),
  2069. yasm_expr_sym(proc_sym), line)));
  2070. yasm_dvs_append(&dvs, yasm_dv_create_expr(
  2071. yasm_expr_create(YASM_EXPR_WRT, yasm_expr_sym(unwindpos),
  2072. yasm_expr_sym(xdata_sym), line)));
  2073. yasm_section_bcs_append(sect, yasm_bc_create_data(&dvs, 4, 0, NULL, line));
  2074. objfmt_coff->proc_frame = 0;
  2075. objfmt_coff->done_prolog = 0;
  2076. }
  2077. /* Define valid debug formats to use with this object format */
  2078. static const char *coff_objfmt_dbgfmt_keywords[] = {
  2079. "null",
  2080. "dwarf2",
  2081. NULL
  2082. };
  2083. static const yasm_directive coff_objfmt_directives[] = {
  2084. { ".ident", "gas", dir_ident, YASM_DIR_ANY },
  2085. { "ident", "nasm", dir_ident, YASM_DIR_ANY },
  2086. { ".def", "gas", dir_def, YASM_DIR_ID_REQUIRED },
  2087. { ".endef", "gas", dir_endef, YASM_DIR_ANY },
  2088. { ".scl", "gas", dir_scl, YASM_DIR_ARG_REQUIRED },
  2089. { ".type", "gas", dir_type, YASM_DIR_ARG_REQUIRED },
  2090. { ".secrel32", "gas", dir_secrel32, YASM_DIR_ARG_REQUIRED },
  2091. { NULL, NULL, NULL, 0 }
  2092. };
  2093. /* Define objfmt structure -- see objfmt.h for details */
  2094. yasm_objfmt_module yasm_coff_LTX_objfmt = {
  2095. "COFF (DJGPP)",
  2096. "coff",
  2097. "o",
  2098. 32,
  2099. 0,
  2100. coff_objfmt_dbgfmt_keywords,
  2101. "null",
  2102. coff_objfmt_directives,
  2103. NULL, /* no standard macros */
  2104. coff_objfmt_create,
  2105. coff_objfmt_output,
  2106. coff_objfmt_destroy,
  2107. coff_objfmt_add_default_section,
  2108. coff_objfmt_init_new_section,
  2109. coff_objfmt_section_switch,
  2110. coff_objfmt_get_special_sym
  2111. };
  2112. /* Define valid debug formats to use with this object format */
  2113. static const char *winXX_objfmt_dbgfmt_keywords[] = {
  2114. "null",
  2115. "dwarf2",
  2116. "cv8",
  2117. NULL
  2118. };
  2119. static const yasm_directive win32_objfmt_directives[] = {
  2120. { ".ident", "gas", dir_ident, YASM_DIR_ANY },
  2121. { "ident", "nasm", dir_ident, YASM_DIR_ANY },
  2122. { ".def", "gas", dir_def, YASM_DIR_ID_REQUIRED },
  2123. { ".endef", "gas", dir_endef, YASM_DIR_ANY },
  2124. { ".scl", "gas", dir_scl, YASM_DIR_ARG_REQUIRED },
  2125. { ".type", "gas", dir_type, YASM_DIR_ARG_REQUIRED },
  2126. { ".secrel32", "gas", dir_secrel32, YASM_DIR_ARG_REQUIRED },
  2127. { ".export", "gas", dir_export, YASM_DIR_ID_REQUIRED },
  2128. { "export", "nasm", dir_export, YASM_DIR_ID_REQUIRED },
  2129. { ".safeseh", "gas", dir_safeseh, YASM_DIR_ID_REQUIRED },
  2130. { "safeseh", "nasm", dir_safeseh, YASM_DIR_ID_REQUIRED },
  2131. { NULL, NULL, NULL, 0 }
  2132. };
  2133. static const char *win32_nasm_stdmac[] = {
  2134. "%imacro export 1+.nolist",
  2135. "[export %1]",
  2136. "%endmacro",
  2137. "%imacro safeseh 1+.nolist",
  2138. "[safeseh %1]",
  2139. "%endmacro",
  2140. NULL
  2141. };
  2142. static const yasm_stdmac win32_objfmt_stdmacs[] = {
  2143. { "nasm", "nasm", win32_nasm_stdmac },
  2144. { NULL, NULL, NULL }
  2145. };
  2146. /* Define objfmt structure -- see objfmt.h for details */
  2147. yasm_objfmt_module yasm_win32_LTX_objfmt = {
  2148. "Win32",
  2149. "win32",
  2150. "obj",
  2151. 32,
  2152. 1,
  2153. winXX_objfmt_dbgfmt_keywords,
  2154. "null",
  2155. win32_objfmt_directives,
  2156. win32_objfmt_stdmacs,
  2157. win32_objfmt_create,
  2158. coff_objfmt_output,
  2159. coff_objfmt_destroy,
  2160. coff_objfmt_add_default_section,
  2161. coff_objfmt_init_new_section,
  2162. coff_objfmt_section_switch,
  2163. coff_objfmt_get_special_sym
  2164. };
  2165. static const yasm_directive win64_objfmt_directives[] = {
  2166. { ".ident", "gas", dir_ident, YASM_DIR_ANY },
  2167. { "ident", "nasm", dir_ident, YASM_DIR_ANY },
  2168. { ".def", "gas", dir_def, YASM_DIR_ID_REQUIRED },
  2169. { ".endef", "gas", dir_endef, YASM_DIR_ANY },
  2170. { ".scl", "gas", dir_scl, YASM_DIR_ARG_REQUIRED },
  2171. { ".type", "gas", dir_type, YASM_DIR_ARG_REQUIRED },
  2172. { ".secrel32", "gas", dir_secrel32, YASM_DIR_ARG_REQUIRED },
  2173. { ".export", "gas", dir_export, YASM_DIR_ID_REQUIRED },
  2174. { "export", "nasm", dir_export, YASM_DIR_ID_REQUIRED },
  2175. { ".proc_frame", "gas", dir_proc_frame, YASM_DIR_ID_REQUIRED },
  2176. { "proc_frame", "nasm", dir_proc_frame, YASM_DIR_ID_REQUIRED },
  2177. { ".pushreg", "gas", dir_pushreg, YASM_DIR_ARG_REQUIRED },
  2178. { "pushreg", "nasm", dir_pushreg, YASM_DIR_ARG_REQUIRED },
  2179. { ".setframe", "gas", dir_setframe, YASM_DIR_ARG_REQUIRED },
  2180. { "setframe", "nasm", dir_setframe, YASM_DIR_ARG_REQUIRED },
  2181. { ".allocstack", "gas", dir_allocstack, YASM_DIR_ARG_REQUIRED },
  2182. { "allocstack", "nasm", dir_allocstack, YASM_DIR_ARG_REQUIRED },
  2183. { ".savereg", "gas", dir_savereg, YASM_DIR_ARG_REQUIRED },
  2184. { "savereg", "nasm", dir_savereg, YASM_DIR_ARG_REQUIRED },
  2185. { ".savexmm128", "gas", dir_savexmm128, YASM_DIR_ARG_REQUIRED },
  2186. { "savexmm128", "nasm", dir_savexmm128, YASM_DIR_ARG_REQUIRED },
  2187. { ".pushframe", "gas", dir_pushframe, YASM_DIR_ANY },
  2188. { "pushframe", "nasm", dir_pushframe, YASM_DIR_ANY },
  2189. { ".endprolog", "gas", dir_endprolog, YASM_DIR_ANY },
  2190. { "endprolog", "nasm", dir_endprolog, YASM_DIR_ANY },
  2191. { ".endproc_frame", "gas", dir_endproc_frame, YASM_DIR_ANY },
  2192. { "endproc_frame", "nasm", dir_endproc_frame, YASM_DIR_ANY },
  2193. { NULL, NULL, NULL, 0 }
  2194. };
  2195. #include "win64-nasm.c"
  2196. #include "win64-gas.c"
  2197. static const yasm_stdmac win64_objfmt_stdmacs[] = {
  2198. { "nasm", "nasm", win64_nasm_stdmac },
  2199. { "gas", "nasm", win64_gas_stdmac },
  2200. { NULL, NULL, NULL }
  2201. };
  2202. /* Define objfmt structure -- see objfmt.h for details */
  2203. yasm_objfmt_module yasm_win64_LTX_objfmt = {
  2204. "Win64",
  2205. "win64",
  2206. "obj",
  2207. 64,
  2208. 1,
  2209. winXX_objfmt_dbgfmt_keywords,
  2210. "null",
  2211. win64_objfmt_directives,
  2212. win64_objfmt_stdmacs,
  2213. win64_objfmt_create,
  2214. coff_objfmt_output,
  2215. coff_objfmt_destroy,
  2216. coff_objfmt_add_default_section,
  2217. coff_objfmt_init_new_section,
  2218. coff_objfmt_section_switch,
  2219. win64_objfmt_get_special_sym
  2220. };
  2221. yasm_objfmt_module yasm_x64_LTX_objfmt = {
  2222. "Win64",
  2223. "x64",
  2224. "obj",
  2225. 64,
  2226. 1,
  2227. winXX_objfmt_dbgfmt_keywords,
  2228. "null",
  2229. win64_objfmt_directives,
  2230. win64_objfmt_stdmacs,
  2231. win64_objfmt_create,
  2232. coff_objfmt_output,
  2233. coff_objfmt_destroy,
  2234. coff_objfmt_add_default_section,
  2235. coff_objfmt_init_new_section,
  2236. coff_objfmt_section_switch,
  2237. win64_objfmt_get_special_sym
  2238. };