codeview.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827
  1. /* ----------------------------------------------------------------------- *
  2. *
  3. * Copyright 1996-2017 The NASM Authors - All Rights Reserved
  4. * See the file AUTHORS included with the NASM distribution for
  5. * the specific copyright holders.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following
  9. * conditions are met:
  10. *
  11. * * Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * * Redistributions in binary form must reproduce the above
  14. * copyright notice, this list of conditions and the following
  15. * disclaimer in the documentation and/or other materials provided
  16. * with the distribution.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  19. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  20. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  21. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  22. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  23. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  25. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  26. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  28. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  29. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  30. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. *
  32. * ----------------------------------------------------------------------- */
  33. /*
  34. * codeview.c Codeview Debug Format support for COFF
  35. */
  36. #include "version.h"
  37. #include "compiler.h"
  38. #include <stdio.h>
  39. #include <stddef.h>
  40. #include <stdlib.h>
  41. #include "nasm.h"
  42. #include "nasmlib.h"
  43. #include "error.h"
  44. #include "preproc.h"
  45. #include "saa.h"
  46. #include "hashtbl.h"
  47. #include "outlib.h"
  48. #include "pecoff.h"
  49. #include "md5.h"
  50. static void cv8_init(void);
  51. static void cv8_linenum(const char *filename, int32_t linenumber,
  52. int32_t segto);
  53. static void cv8_deflabel(char *name, int32_t segment, int64_t offset,
  54. int is_global, char *special);
  55. static void cv8_typevalue(int32_t type);
  56. static void cv8_output(int type, void *param);
  57. static void cv8_cleanup(void);
  58. const struct dfmt df_cv8 = {
  59. "Codeview 8", /* .fullname */
  60. "cv8", /* .shortname */
  61. cv8_init, /* .init */
  62. cv8_linenum, /* .linenum */
  63. cv8_deflabel, /* .debug_deflabel */
  64. null_debug_directive, /* .debug_directive */
  65. cv8_typevalue, /* .debug_typevalue */
  66. cv8_output, /* .debug_output */
  67. cv8_cleanup, /* .cleanup */
  68. NULL /* pragma list */
  69. };
  70. /*******************************************************************************
  71. * dfmt callbacks
  72. ******************************************************************************/
  73. struct source_file;
  74. struct source_file {
  75. const char *filename;
  76. char *fullname;
  77. uint32_t fullnamelen;
  78. struct source_file *next;
  79. uint32_t filetbl_off;
  80. uint32_t sourcetbl_off;
  81. struct SAA *lines;
  82. uint32_t num_lines;
  83. unsigned char md5sum[MD5_HASHBYTES];
  84. };
  85. struct linepair {
  86. uint32_t file_offset;
  87. uint32_t linenumber;
  88. };
  89. enum symbol_type {
  90. SYMTYPE_CODE,
  91. SYMTYPE_PROC,
  92. SYMTYPE_LDATA,
  93. SYMTYPE_GDATA,
  94. SYMTYPE_MAX
  95. };
  96. struct cv8_symbol {
  97. enum symbol_type type;
  98. char *name;
  99. uint32_t secrel;
  100. uint16_t section;
  101. uint32_t size;
  102. uint32_t typeindex;
  103. enum symtype {
  104. TYPE_UNREGISTERED = 0x0000, /* T_NOTYPE */
  105. TYPE_BYTE = 0x0020,
  106. TYPE_WORD = 0x0021,
  107. TYPE_DWORD= 0x0022,
  108. TYPE_QUAD = 0x0023,
  109. TYPE_REAL32 = 0x0040,
  110. TYPE_REAL64 = 0x0041,
  111. TYPE_REAL80 = 0x0042,
  112. TYPE_REAL128= 0x0043,
  113. TYPE_REAL256= 0x0044,
  114. TYPE_REAL512= 0x0045
  115. } symtype;
  116. };
  117. struct cv8_state {
  118. int symbol_sect;
  119. int type_sect;
  120. uint32_t text_offset;
  121. struct source_file *source_files, **source_files_tail;
  122. const char *last_filename;
  123. struct source_file *last_source_file;
  124. struct hash_table file_hash;
  125. unsigned num_files;
  126. uint32_t total_filename_len;
  127. unsigned total_lines;
  128. struct SAA *symbols;
  129. struct cv8_symbol *last_sym;
  130. unsigned num_syms[SYMTYPE_MAX];
  131. unsigned symbol_lengths;
  132. unsigned total_syms;
  133. struct {
  134. char *name;
  135. size_t namebytes;
  136. } outfile;
  137. };
  138. struct cv8_state cv8_state;
  139. static void cv8_init(void)
  140. {
  141. const uint32_t sect_flags = IMAGE_SCN_MEM_READ |
  142. IMAGE_SCN_MEM_DISCARDABLE |
  143. IMAGE_SCN_CNT_INITIALIZED_DATA |
  144. IMAGE_SCN_ALIGN_1BYTES;
  145. cv8_state.symbol_sect = coff_make_section(".debug$S", sect_flags);
  146. cv8_state.type_sect = coff_make_section(".debug$T", sect_flags);
  147. cv8_state.text_offset = 0;
  148. cv8_state.source_files = NULL;
  149. cv8_state.source_files_tail = &cv8_state.source_files;
  150. hash_init(&cv8_state.file_hash, HASH_MEDIUM);
  151. cv8_state.num_files = 0;
  152. cv8_state.total_filename_len = 0;
  153. cv8_state.total_lines = 0;
  154. cv8_state.symbols = saa_init(sizeof(struct cv8_symbol));
  155. cv8_state.last_sym = NULL;
  156. }
  157. static struct source_file *register_file(const char *filename);
  158. static struct coff_Section *find_section(int32_t segto);
  159. static void cv8_linenum(const char *filename, int32_t linenumber,
  160. int32_t segto)
  161. {
  162. struct coff_Section *s;
  163. struct linepair *li;
  164. struct source_file *file;
  165. file = register_file(filename);
  166. s = find_section(segto);
  167. if (s == NULL)
  168. return;
  169. if ((s->flags & IMAGE_SCN_MEM_EXECUTE) == 0)
  170. return;
  171. li = saa_wstruct(file->lines);
  172. li->file_offset = cv8_state.text_offset;
  173. li->linenumber = linenumber;
  174. file->num_lines++;
  175. cv8_state.total_lines++;
  176. }
  177. static void cv8_deflabel(char *name, int32_t segment, int64_t offset,
  178. int is_global, char *special)
  179. {
  180. struct cv8_symbol *sym;
  181. struct coff_Section *s;
  182. (void)special;
  183. s = find_section(segment);
  184. if (s == NULL)
  185. return;
  186. sym = saa_wstruct(cv8_state.symbols);
  187. if (s->flags & IMAGE_SCN_MEM_EXECUTE)
  188. sym->type = is_global ? SYMTYPE_PROC : SYMTYPE_CODE;
  189. else
  190. sym->type = is_global ? SYMTYPE_GDATA : SYMTYPE_LDATA;
  191. cv8_state.num_syms[sym->type]++;
  192. cv8_state.total_syms++;
  193. sym->section = segment;
  194. sym->secrel = offset;
  195. sym->symtype = TYPE_UNREGISTERED;
  196. sym->size = 0;
  197. sym->typeindex = 0;
  198. sym->name = nasm_strdup(name);
  199. cv8_state.symbol_lengths += strlen(sym->name) + 1;
  200. if (cv8_state.last_sym && cv8_state.last_sym->section == segment)
  201. cv8_state.last_sym->size = offset - cv8_state.last_sym->secrel;
  202. cv8_state.last_sym = sym;
  203. }
  204. static void cv8_typevalue(int32_t type)
  205. {
  206. if (!cv8_state.last_sym)
  207. return;
  208. if (cv8_state.last_sym->symtype != TYPE_UNREGISTERED)
  209. return;
  210. switch (TYM_TYPE(type)) {
  211. case TY_BYTE:
  212. cv8_state.last_sym->symtype = TYPE_BYTE;
  213. break;
  214. case TY_WORD:
  215. cv8_state.last_sym->symtype = TYPE_WORD;
  216. break;
  217. case TY_DWORD:
  218. cv8_state.last_sym->symtype = TYPE_DWORD;
  219. break;
  220. case TY_QWORD:
  221. cv8_state.last_sym->symtype = TYPE_QUAD;
  222. break;
  223. case TY_FLOAT:
  224. cv8_state.last_sym->symtype = TYPE_REAL32;
  225. break;
  226. case TY_TBYTE:
  227. cv8_state.last_sym->symtype = TYPE_REAL80;
  228. break;
  229. case TY_OWORD:
  230. cv8_state.last_sym->symtype = TYPE_REAL128;
  231. break;
  232. case TY_YWORD:
  233. cv8_state.last_sym->symtype = TYPE_REAL256;
  234. break;
  235. case TY_ZWORD:
  236. cv8_state.last_sym->symtype = TYPE_REAL512;
  237. break;
  238. case TY_UNKNOWN:
  239. break;
  240. case TY_LABEL:
  241. break;
  242. }
  243. }
  244. static void cv8_output(int type, void *param)
  245. {
  246. struct coff_DebugInfo *dinfo = param;
  247. (void)type;
  248. if (dinfo->section && dinfo->section->name &&
  249. !strncmp(dinfo->section->name, ".text", 5))
  250. cv8_state.text_offset += dinfo->size;
  251. }
  252. static void build_symbol_table(struct coff_Section *const sect);
  253. static void build_type_table(struct coff_Section *const sect);
  254. static void cv8_cleanup(void)
  255. {
  256. struct cv8_symbol *sym;
  257. struct source_file *file;
  258. struct coff_Section *symbol_sect = coff_sects[cv8_state.symbol_sect];
  259. struct coff_Section *type_sect = coff_sects[cv8_state.type_sect];
  260. cv8_state.outfile.name = nasm_realpath(outname);
  261. cv8_state.outfile.namebytes = strlen(cv8_state.outfile.name) + 1;
  262. build_symbol_table(symbol_sect);
  263. build_type_table(type_sect);
  264. list_for_each(file, cv8_state.source_files) {
  265. nasm_free(file->fullname);
  266. saa_free(file->lines);
  267. free(file);
  268. }
  269. hash_free(&cv8_state.file_hash);
  270. saa_rewind(cv8_state.symbols);
  271. while ((sym = saa_rstruct(cv8_state.symbols)))
  272. nasm_free(sym->name);
  273. saa_free(cv8_state.symbols);
  274. nasm_free(cv8_state.outfile.name);
  275. }
  276. /*******************************************************************************
  277. * implementation
  278. ******************************************************************************/
  279. static void calc_md5(const char *const filename,
  280. unsigned char sum[MD5_HASHBYTES])
  281. {
  282. int success = 0;
  283. unsigned char *file_buf;
  284. FILE *f;
  285. MD5_CTX ctx;
  286. f = pp_input_fopen(filename, NF_BINARY);
  287. if (!f)
  288. goto done;
  289. file_buf = nasm_zalloc(BUFSIZ);
  290. MD5Init(&ctx);
  291. while (!feof(f)) {
  292. size_t i = fread(file_buf, 1, BUFSIZ, f);
  293. if (ferror(f))
  294. goto done_0;
  295. else if (i == 0)
  296. break;
  297. MD5Update(&ctx, file_buf, i);
  298. }
  299. MD5Final(sum, &ctx);
  300. success = 1;
  301. done_0:
  302. nasm_free(file_buf);
  303. fclose(f);
  304. done:
  305. if (!success) {
  306. nasm_error(ERR_NONFATAL, "unable to hash file %s. "
  307. "Debug information may be unavailable.\n",
  308. filename);
  309. }
  310. return;
  311. }
  312. static struct source_file *register_file(const char *filename)
  313. {
  314. struct source_file *file;
  315. void **filep;
  316. char *fullpath;
  317. struct hash_insert hi;
  318. /*
  319. * The common case is that we are invoked with the same filename
  320. * as we were last time. Make this a pointer comparison: this is
  321. * safe because the NASM core code allocates each filename once
  322. * and never frees it.
  323. */
  324. if (likely(cv8_state.last_filename == filename))
  325. return cv8_state.last_source_file;
  326. cv8_state.last_filename = filename;
  327. filep = hash_find(&cv8_state.file_hash, filename, &hi);
  328. if (likely(filep)) {
  329. file = *filep;
  330. } else {
  331. /* New filename encounter */
  332. fullpath = nasm_realpath(filename);
  333. file = nasm_zalloc(sizeof(*file));
  334. file->filename = filename;
  335. file->fullname = fullpath;
  336. file->fullnamelen = strlen(fullpath);
  337. file->lines = saa_init(sizeof(struct linepair));
  338. *cv8_state.source_files_tail = file;
  339. cv8_state.source_files_tail = &file->next;
  340. calc_md5(fullpath, file->md5sum);
  341. hash_add(&hi, filename, file);
  342. cv8_state.num_files++;
  343. cv8_state.total_filename_len += file->fullnamelen + 1;
  344. }
  345. cv8_state.last_source_file = file;
  346. return file;
  347. }
  348. static struct coff_Section *find_section(int32_t segto)
  349. {
  350. int i;
  351. for (i = 0; i < coff_nsects; i++) {
  352. struct coff_Section *sec;
  353. sec = coff_sects[i];
  354. if (segto == sec->index)
  355. return sec;
  356. }
  357. return NULL;
  358. }
  359. static void register_reloc(struct coff_Section *const sect,
  360. char *sym, uint32_t addr, uint16_t type)
  361. {
  362. struct coff_Reloc *r;
  363. struct coff_Section *sec;
  364. uint32_t i;
  365. r = *sect->tail = nasm_malloc(sizeof(struct coff_Reloc));
  366. sect->tail = &r->next;
  367. r->next = NULL;
  368. sect->nrelocs++;
  369. r->address = addr;
  370. r->symbase = SECT_SYMBOLS;
  371. r->type = type;
  372. r->symbol = 0;
  373. for (i = 0; i < (uint32_t)coff_nsects; i++) {
  374. sec = coff_sects[i];
  375. if (!strcmp(sym, sec->name)) {
  376. return;
  377. }
  378. r->symbol += 2;
  379. }
  380. saa_rewind(coff_syms);
  381. for (i = 0; i < coff_nsyms; i++) {
  382. struct coff_Symbol *s = saa_rstruct(coff_syms);
  383. r->symbol++;
  384. if (s->strpos == -1 && !strcmp(sym, s->name)) {
  385. return;
  386. } else if (s->strpos != -1) {
  387. int res;
  388. char *symname;
  389. symname = nasm_malloc(s->namlen + 1);
  390. saa_fread(coff_strs, s->strpos-4, symname, s->namlen);
  391. symname[s->namlen] = '\0';
  392. res = strcmp(sym, symname);
  393. nasm_free(symname);
  394. if (!res)
  395. return;
  396. }
  397. }
  398. nasm_panic(0, "codeview: relocation for unregistered symbol: %s", sym);
  399. }
  400. static inline void section_write32(struct coff_Section *sect, uint32_t val)
  401. {
  402. saa_write32(sect->data, val);
  403. sect->len += 4;
  404. }
  405. static inline void section_write16(struct coff_Section *sect, uint16_t val)
  406. {
  407. saa_write16(sect->data, val);
  408. sect->len += 2;
  409. }
  410. static inline void section_write8(struct coff_Section *sect, uint8_t val)
  411. {
  412. saa_write8(sect->data, val);
  413. sect->len++;
  414. }
  415. static inline void section_wbytes(struct coff_Section *sect, const void *buf,
  416. size_t len)
  417. {
  418. saa_wbytes(sect->data, buf, len);
  419. sect->len += len;
  420. }
  421. static void write_filename_table(struct coff_Section *const sect)
  422. {
  423. uint32_t field_length;
  424. uint32_t tbl_off = 1; /* offset starts at 1 to skip NULL entry */
  425. struct source_file *file;
  426. nasm_assert(cv8_state.source_files != NULL);
  427. nasm_assert(cv8_state.num_files > 0);
  428. nasm_assert(cv8_state.total_filename_len > 0);
  429. field_length = 1 + cv8_state.total_filename_len;
  430. section_write32(sect, 0x000000F3);
  431. section_write32(sect, field_length);
  432. section_write8(sect, 0);
  433. list_for_each(file, cv8_state.source_files) {
  434. section_wbytes(sect, file->fullname, file->fullnamelen + 1);
  435. file->filetbl_off = tbl_off;
  436. tbl_off += file->fullnamelen + 1;
  437. }
  438. }
  439. static void write_sourcefile_table(struct coff_Section *const sect)
  440. {
  441. const uint32_t entry_size = 4 + 2 + MD5_HASHBYTES + 2;
  442. uint32_t field_length = 0;
  443. uint32_t tbl_off = 0;
  444. struct source_file *file;
  445. field_length = entry_size * cv8_state.num_files;
  446. section_write32(sect, 0x000000F4);
  447. section_write32(sect, field_length);
  448. list_for_each(file, cv8_state.source_files) {
  449. nasm_assert(file->filetbl_off > 0);
  450. section_write32(sect, file->filetbl_off);
  451. section_write16(sect, 0x0110);
  452. section_wbytes(sect, file->md5sum, MD5_HASHBYTES);
  453. section_write16(sect, 0);
  454. file->sourcetbl_off = tbl_off;
  455. tbl_off += entry_size;
  456. }
  457. }
  458. static void write_linenumber_table(struct coff_Section *const sect)
  459. {
  460. const uint32_t file_field_len = 12;
  461. const uint32_t line_field_len = 8;
  462. int i;
  463. uint32_t field_length = 0;
  464. size_t field_base;
  465. struct source_file *file;
  466. struct coff_Section *s;
  467. for (i = 0; i < coff_nsects; i++) {
  468. if (!strncmp(coff_sects[i]->name, ".text", 5))
  469. break;
  470. }
  471. if (i == coff_nsects)
  472. return;
  473. s = coff_sects[i];
  474. field_length = 12;
  475. field_length += (cv8_state.num_files * file_field_len);
  476. field_length += (cv8_state.total_lines * line_field_len);
  477. section_write32(sect, 0x000000F2);
  478. section_write32(sect, field_length);
  479. field_base = sect->len;
  480. section_write32(sect, 0); /* SECREL, updated by relocation */
  481. section_write16(sect, 0); /* SECTION, updated by relocation*/
  482. section_write16(sect, 0); /* pad */
  483. section_write32(sect, s->len);
  484. register_reloc(sect, ".text", field_base,
  485. win64 ? IMAGE_REL_AMD64_SECREL : IMAGE_REL_I386_SECREL);
  486. register_reloc(sect, ".text", field_base + 4,
  487. win64 ? IMAGE_REL_AMD64_SECTION : IMAGE_REL_I386_SECTION);
  488. list_for_each(file, cv8_state.source_files) {
  489. struct linepair *li;
  490. /* source mapping */
  491. section_write32(sect, file->sourcetbl_off);
  492. section_write32(sect, file->num_lines);
  493. section_write32(sect, file_field_len + (file->num_lines * line_field_len));
  494. /* the pairs */
  495. saa_rewind(file->lines);
  496. while ((li = saa_rstruct(file->lines))) {
  497. section_write32(sect, li->file_offset);
  498. section_write32(sect, li->linenumber |= 0x80000000);
  499. }
  500. }
  501. }
  502. static uint16_t write_symbolinfo_obj(struct coff_Section *sect)
  503. {
  504. uint16_t obj_len;
  505. obj_len = 2 + 4 + cv8_state.outfile.namebytes;
  506. section_write16(sect, obj_len);
  507. section_write16(sect, 0x1101);
  508. section_write32(sect, 0); /* ASM language */
  509. section_wbytes(sect, cv8_state.outfile.name, cv8_state.outfile.namebytes);
  510. return obj_len;
  511. }
  512. static uint16_t write_symbolinfo_properties(struct coff_Section *sect,
  513. const char *const creator_str)
  514. {
  515. /* https://github.com/Microsoft/microsoft-pdb/blob/1d60e041/include/cvinfo.h#L3313 */
  516. uint16_t creator_len;
  517. creator_len = 2 + 4 + 2 + 3*2 + 3*2 + strlen(creator_str)+1 + 2;
  518. /*
  519. * We used to use a language ID of 3 for "MASM", since it's closest of the
  520. * options available; however, BinScope from WACK (the Windows Application
  521. * Certification Kit) tests for specific minimum MASM versions and trying to
  522. * match an increasing sequence of random MASM version/build numbers seems
  523. * like a fool's errand.
  524. *
  525. * Instead, use a different language ID (NASM is, after all, not MASM
  526. * syntax) and just write the actual NASM version number. BinScope appears
  527. * to be happy with that.
  528. */
  529. section_write16(sect, creator_len);
  530. section_write16(sect, 0x1116);
  531. section_write32(sect, 'N'); /* language: 'N' (0x4e) for "NASM"; flags are 0 */
  532. if (win64)
  533. section_write16(sect, 0x00D0); /* machine */
  534. else if (win32)
  535. section_write16(sect, 0x0006); /* machine */
  536. else
  537. nasm_assert(!"neither win32 nor win64 are set!");
  538. section_write16(sect, 0); /* verFEMajor */
  539. section_write16(sect, 0); /* verFEMinor */
  540. section_write16(sect, 0); /* verFEBuild */
  541. /* BinScope/WACK insist on version >= 8.0.50727 */
  542. section_write16(sect, NASM_MAJOR_VER); /* verMajor */
  543. section_write16(sect, NASM_MINOR_VER); /* verMinor */
  544. section_write16(sect, NASM_SUBMINOR_VER*100 + NASM_PATCHLEVEL_VER); /* verBuild */
  545. section_wbytes(sect, creator_str, strlen(creator_str)+1); /* verSt */
  546. /*
  547. * normally there would be key/value pairs here, but they aren't
  548. * necessary. They are terminated by 2B
  549. */
  550. section_write16(sect, 0);
  551. return creator_len;
  552. }
  553. static uint16_t write_symbolinfo_symbols(struct coff_Section *sect)
  554. {
  555. uint16_t len = 0, field_len;
  556. uint32_t field_base;
  557. struct cv8_symbol *sym;
  558. saa_rewind(cv8_state.symbols);
  559. while ((sym = saa_rstruct(cv8_state.symbols))) {
  560. switch (sym->type) {
  561. case SYMTYPE_LDATA:
  562. case SYMTYPE_GDATA:
  563. field_len = 12 + strlen(sym->name) + 1;
  564. len += field_len - 2;
  565. section_write16(sect, field_len);
  566. if (sym->type == SYMTYPE_LDATA)
  567. section_write16(sect, 0x110C);
  568. else
  569. section_write16(sect, 0x110D);
  570. section_write32(sect, sym->symtype);
  571. field_base = sect->len;
  572. section_write32(sect, 0); /* SECREL */
  573. section_write16(sect, 0); /* SECTION */
  574. break;
  575. case SYMTYPE_PROC:
  576. case SYMTYPE_CODE:
  577. field_len = 9 + strlen(sym->name) + 1;
  578. len += field_len - 2;
  579. section_write16(sect, field_len);
  580. section_write16(sect, 0x1105);
  581. field_base = sect->len;
  582. section_write32(sect, 0); /* SECREL */
  583. section_write16(sect, 0); /* SECTION */
  584. section_write8(sect, 0); /* FLAG */
  585. break;
  586. default:
  587. nasm_assert(!"unknown symbol type");
  588. }
  589. section_wbytes(sect, sym->name, strlen(sym->name) + 1);
  590. register_reloc(sect, sym->name, field_base,
  591. win64 ? IMAGE_REL_AMD64_SECREL :
  592. IMAGE_REL_I386_SECREL);
  593. register_reloc(sect, sym->name, field_base + 4,
  594. win64 ? IMAGE_REL_AMD64_SECTION :
  595. IMAGE_REL_I386_SECTION);
  596. }
  597. return len;
  598. }
  599. static void write_symbolinfo_table(struct coff_Section *const sect)
  600. {
  601. static const char creator_str[] = "The Netwide Assembler " NASM_VER;
  602. uint16_t obj_length, creator_length, sym_length;
  603. uint32_t field_length = 0, out_len;
  604. nasm_assert(cv8_state.outfile.namebytes);
  605. /* signature, language, outfile NULL */
  606. obj_length = 2 + 4 + cv8_state.outfile.namebytes;
  607. creator_length = 2 + 4 + 2 + 3*2 + 3*2 + strlen(creator_str)+1 + 2;
  608. sym_length = ( cv8_state.num_syms[SYMTYPE_CODE] * 7) +
  609. ( cv8_state.num_syms[SYMTYPE_PROC] * 7) +
  610. ( cv8_state.num_syms[SYMTYPE_LDATA] * 10) +
  611. ( cv8_state.num_syms[SYMTYPE_GDATA] * 10) +
  612. cv8_state.symbol_lengths;
  613. field_length = 2 + obj_length +
  614. 2 + creator_length +
  615. (4 * cv8_state.total_syms) + sym_length;
  616. section_write32(sect, 0x000000F1);
  617. section_write32(sect, field_length);
  618. /* for sub fields, length preceeds type */
  619. out_len = write_symbolinfo_obj(sect);
  620. nasm_assert(out_len == obj_length);
  621. out_len = write_symbolinfo_properties(sect, creator_str);
  622. nasm_assert(out_len == creator_length);
  623. out_len = write_symbolinfo_symbols(sect);
  624. nasm_assert(out_len == sym_length);
  625. }
  626. static inline void align4_table(struct coff_Section *const sect)
  627. {
  628. unsigned diff;
  629. uint32_t zero = 0;
  630. struct SAA *data = sect->data;
  631. if (data->wptr % 4 == 0)
  632. return;
  633. diff = 4 - (data->wptr % 4);
  634. if (diff)
  635. section_wbytes(sect, &zero, diff);
  636. }
  637. static void build_symbol_table(struct coff_Section *const sect)
  638. {
  639. section_write32(sect, 0x00000004);
  640. write_filename_table(sect);
  641. align4_table(sect);
  642. write_sourcefile_table(sect);
  643. align4_table(sect);
  644. write_linenumber_table(sect);
  645. align4_table(sect);
  646. write_symbolinfo_table(sect);
  647. align4_table(sect);
  648. }
  649. static void build_type_table(struct coff_Section *const sect)
  650. {
  651. uint16_t field_len;
  652. struct cv8_symbol *sym;
  653. section_write32(sect, 0x00000004);
  654. saa_rewind(cv8_state.symbols);
  655. while ((sym = saa_rstruct(cv8_state.symbols))) {
  656. if (sym->type != SYMTYPE_PROC)
  657. continue;
  658. /* proc leaf */
  659. field_len = 2 + 4 + 4 + 4 + 2;
  660. section_write16(sect, field_len);
  661. section_write16(sect, 0x1008); /* PROC type */
  662. section_write32(sect, 0x00000003); /* return type */
  663. section_write32(sect, 0); /* calling convention (default) */
  664. section_write32(sect, sym->typeindex);
  665. section_write16(sect, 0); /* # params */
  666. /* arglist */
  667. field_len = 2 + 4;
  668. section_write16(sect, field_len);
  669. section_write16(sect, 0x1201); /* ARGLIST */
  670. section_write32(sect, 0); /*num params */
  671. }
  672. }