config/msvc.h: inttypes.h and stdbool.h introduced in MSVS 2013
[nasm.git] / output / codeview.c
blob86f63a7000e0e0309bac62270d988dae6cf96267
1 /* ----------------------------------------------------------------------- *
3 * Copyright 1996-2016 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
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.
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.
32 * ----------------------------------------------------------------------- */
35 * codeview.c Codeview Debug Format support for COFF
38 #include "version.h"
39 #include "compiler.h"
41 #include <stdio.h>
42 #include <stddef.h>
43 #include <stdlib.h>
45 #include "nasm.h"
46 #include "nasmlib.h"
47 #include "preproc.h"
48 #include "saa.h"
49 #include "hashtbl.h"
50 #include "outlib.h"
51 #include "pecoff.h"
52 #include "md5.h"
54 static void cv8_init(void);
55 static void cv8_linenum(const char *filename, int32_t linenumber,
56 int32_t segto);
57 static void cv8_deflabel(char *name, int32_t segment, int64_t offset,
58 int is_global, char *special);
59 static void cv8_typevalue(int32_t type);
60 static void cv8_output(int type, void *param);
61 static void cv8_cleanup(void);
63 const struct dfmt df_cv8 = {
64 "Codeview 8", /* .fullname */
65 "cv8", /* .shortname */
66 cv8_init, /* .init */
67 cv8_linenum, /* .linenum */
68 cv8_deflabel, /* .debug_deflabel */
69 null_debug_directive, /* .debug_directive */
70 cv8_typevalue, /* .debug_typevalue */
71 cv8_output, /* .debug_output */
72 cv8_cleanup, /* .cleanup */
75 /*******************************************************************************
76 * dfmt callbacks
77 ******************************************************************************/
78 struct source_file;
80 struct source_file {
81 const char *filename;
82 char *fullname;
83 uint32_t fullnamelen;
85 struct source_file *next;
87 uint32_t filetbl_off;
88 uint32_t sourcetbl_off;
90 struct SAA *lines;
91 uint32_t num_lines;
93 unsigned char md5sum[MD5_HASHBYTES];
96 struct linepair {
97 uint32_t file_offset;
98 uint32_t linenumber;
101 enum symbol_type {
102 SYMTYPE_CODE,
103 SYMTYPE_PROC,
104 SYMTYPE_LDATA,
105 SYMTYPE_GDATA,
107 SYMTYPE_MAX
110 struct cv8_symbol {
111 enum symbol_type type;
112 char *name;
114 uint32_t secrel;
115 uint16_t section;
116 uint32_t size;
117 uint32_t typeindex;
119 enum symtype {
120 TYPE_UNREGISTERED = 0x0000, /* T_NOTYPE */
121 TYPE_BYTE = 0x0020,
122 TYPE_WORD = 0x0021,
123 TYPE_DWORD= 0x0022,
124 TYPE_QUAD = 0x0023,
126 TYPE_REAL32 = 0x0040,
127 TYPE_REAL64 = 0x0041,
128 TYPE_REAL80 = 0x0042,
129 TYPE_REAL128= 0x0043,
130 TYPE_REAL256= 0x0044,
131 TYPE_REAL512= 0x0045
132 } symtype;
135 struct cv8_state {
136 int symbol_sect;
137 int type_sect;
139 uint32_t text_offset;
141 struct source_file *source_files, **source_files_tail;
142 const char *last_filename;
143 struct source_file *last_source_file;
144 struct hash_table file_hash;
145 unsigned num_files;
146 uint32_t total_filename_len;
149 unsigned total_lines;
151 struct SAA *symbols;
152 struct cv8_symbol *last_sym;
153 unsigned num_syms[SYMTYPE_MAX];
154 unsigned symbol_lengths;
155 unsigned total_syms;
157 struct {
158 char *name;
159 size_t namebytes;
160 } outfile;
162 struct cv8_state cv8_state;
164 static void cv8_init(void)
166 const uint32_t sect_flags = IMAGE_SCN_MEM_READ |
167 IMAGE_SCN_MEM_DISCARDABLE |
168 IMAGE_SCN_CNT_INITIALIZED_DATA |
169 IMAGE_SCN_ALIGN_1BYTES;
171 cv8_state.symbol_sect = coff_make_section(".debug$S", sect_flags);
172 cv8_state.type_sect = coff_make_section(".debug$T", sect_flags);
174 cv8_state.text_offset = 0;
176 cv8_state.source_files = NULL;
177 cv8_state.source_files_tail = &cv8_state.source_files;
178 hash_init(&cv8_state.file_hash, HASH_MEDIUM);
180 cv8_state.num_files = 0;
181 cv8_state.total_filename_len = 0;
183 cv8_state.total_lines = 0;
185 cv8_state.symbols = saa_init(sizeof(struct cv8_symbol));
186 cv8_state.last_sym = NULL;
189 static struct source_file *register_file(const char *filename);
190 static struct coff_Section *find_section(int32_t segto);
192 static void cv8_linenum(const char *filename, int32_t linenumber,
193 int32_t segto)
195 struct coff_Section *s;
196 struct linepair *li;
197 struct source_file *file;
199 file = register_file(filename);
201 s = find_section(segto);
202 if (s == NULL)
203 return;
205 if ((s->flags & IMAGE_SCN_MEM_EXECUTE) == 0)
206 return;
208 li = saa_wstruct(file->lines);
209 li->file_offset = cv8_state.text_offset;
210 li->linenumber = linenumber;
212 file->num_lines++;
213 cv8_state.total_lines++;
216 static void cv8_deflabel(char *name, int32_t segment, int64_t offset,
217 int is_global, char *special)
219 struct cv8_symbol *sym;
220 struct coff_Section *s;
222 (void)special;
224 s = find_section(segment);
225 if (s == NULL)
226 return;
228 sym = saa_wstruct(cv8_state.symbols);
230 if (s->flags & IMAGE_SCN_MEM_EXECUTE)
231 sym->type = is_global ? SYMTYPE_PROC : SYMTYPE_CODE;
232 else
233 sym->type = is_global ? SYMTYPE_GDATA : SYMTYPE_LDATA;
234 cv8_state.num_syms[sym->type]++;
235 cv8_state.total_syms++;
237 sym->section = segment;
238 sym->secrel = offset;
239 sym->symtype = TYPE_UNREGISTERED;
240 sym->size = 0;
241 sym->typeindex = 0;
243 sym->name = nasm_strdup(name);
244 cv8_state.symbol_lengths += strlen(sym->name) + 1;
246 if (cv8_state.last_sym && cv8_state.last_sym->section == segment)
247 cv8_state.last_sym->size = offset - cv8_state.last_sym->secrel;
248 cv8_state.last_sym = sym;
251 static void cv8_typevalue(int32_t type)
253 if (!cv8_state.last_sym)
254 return;
255 if (cv8_state.last_sym->symtype != TYPE_UNREGISTERED)
256 return;
258 switch (TYM_TYPE(type)) {
259 case TY_BYTE:
260 cv8_state.last_sym->symtype = TYPE_BYTE;
261 break;
262 case TY_WORD:
263 cv8_state.last_sym->symtype = TYPE_WORD;
264 break;
265 case TY_DWORD:
266 cv8_state.last_sym->symtype = TYPE_DWORD;
267 break;
268 case TY_QWORD:
269 cv8_state.last_sym->symtype = TYPE_QUAD;
270 break;
271 case TY_FLOAT:
272 cv8_state.last_sym->symtype = TYPE_REAL32;
273 break;
274 case TY_TBYTE:
275 cv8_state.last_sym->symtype = TYPE_REAL80;
276 break;
277 case TY_OWORD:
278 cv8_state.last_sym->symtype = TYPE_REAL128;
279 break;
280 case TY_YWORD:
281 cv8_state.last_sym->symtype = TYPE_REAL256;
282 break;
283 case TY_UNKNOWN:
284 break;
285 case TY_LABEL:
286 break;
290 static void cv8_output(int type, void *param)
292 struct coff_DebugInfo *dinfo = param;
294 (void)type;
296 if (dinfo->section && dinfo->section->name &&
297 !strncmp(dinfo->section->name, ".text", 5))
298 cv8_state.text_offset += dinfo->size;
301 static void build_symbol_table(struct coff_Section *const sect);
302 static void build_type_table(struct coff_Section *const sect);
304 static void cv8_cleanup(void)
306 struct cv8_symbol *sym;
307 struct source_file *file;
309 struct coff_Section *symbol_sect = coff_sects[cv8_state.symbol_sect];
310 struct coff_Section *type_sect = coff_sects[cv8_state.type_sect];
312 cv8_state.outfile.name = nasm_realpath(coff_outfile);
313 cv8_state.outfile.namebytes = strlen(cv8_state.outfile.name) + 1;
315 build_symbol_table(symbol_sect);
316 build_type_table(type_sect);
318 list_for_each(file, cv8_state.source_files) {
319 nasm_free(file->fullname);
320 saa_free(file->lines);
321 free(file);
323 hash_free(&cv8_state.file_hash);
325 saa_rewind(cv8_state.symbols);
326 while ((sym = saa_rstruct(cv8_state.symbols)))
327 nasm_free(sym->name);
328 saa_free(cv8_state.symbols);
330 nasm_free(cv8_state.outfile.name);
333 /*******************************************************************************
334 * implementation
335 ******************************************************************************/
336 static void calc_md5(const char *const filename,
337 unsigned char sum[MD5_HASHBYTES])
339 int success = 0;
340 unsigned char *file_buf;
341 FILE *f;
342 MD5_CTX ctx;
344 f = pp_input_fopen(filename, NF_BINARY);
345 if (!f)
346 goto done;
348 file_buf = nasm_zalloc(BUFSIZ);
350 MD5Init(&ctx);
351 while (!feof(f)) {
352 size_t i = fread(file_buf, 1, BUFSIZ, f);
353 if (ferror(f))
354 goto done_0;
355 else if (i == 0)
356 break;
357 MD5Update(&ctx, file_buf, i);
359 MD5Final(sum, &ctx);
361 success = 1;
362 done_0:
363 nasm_free(file_buf);
364 fclose(f);
365 done:
366 if (!success) {
367 nasm_error(ERR_NONFATAL, "unable to hash file %s. "
368 "Debug information may be unavailable.\n",
369 filename);
371 return;
374 static struct source_file *register_file(const char *filename)
376 struct source_file *file;
377 void **filep;
378 char *fullpath;
379 struct hash_insert hi;
382 * The common case is that we are invoked with the same filename
383 * as we were last time. Make this a pointer comparison: this is
384 * safe because the NASM core code allocates each filename once
385 * and never frees it.
387 if (likely(cv8_state.last_filename == filename))
388 return cv8_state.last_source_file;
390 cv8_state.last_filename = filename;
392 filep = hash_find(&cv8_state.file_hash, filename, &hi);
393 if (likely(filep)) {
394 file = *filep;
395 } else {
396 /* New filename encounter */
398 fullpath = nasm_realpath(filename);
400 file = nasm_zalloc(sizeof(*file));
402 file->filename = filename;
403 file->fullname = fullpath;
404 file->fullnamelen = strlen(fullpath);
405 file->lines = saa_init(sizeof(struct linepair));
406 *cv8_state.source_files_tail = file;
407 cv8_state.source_files_tail = &file->next;
408 calc_md5(fullpath, file->md5sum);
410 hash_add(&hi, filename, file);
412 cv8_state.num_files++;
413 cv8_state.total_filename_len += file->fullnamelen + 1;
416 cv8_state.last_source_file = file;
417 return file;
420 static struct coff_Section *find_section(int32_t segto)
422 int i;
424 for (i = 0; i < coff_nsects; i++) {
425 struct coff_Section *sec;
427 sec = coff_sects[i];
428 if (segto == sec->index)
429 return sec;
431 return NULL;
434 static void register_reloc(struct coff_Section *const sect,
435 char *sym, uint32_t addr, uint16_t type)
437 struct coff_Reloc *r;
438 struct coff_Section *sec;
440 r = *sect->tail = nasm_malloc(sizeof(struct coff_Reloc));
441 sect->tail = &r->next;
442 r->next = NULL;
443 sect->nrelocs++;
445 r->address = addr;
446 r->symbase = SECT_SYMBOLS;
447 r->type = type;
449 r->symbol = 0;
450 for (int i = 0; i < coff_nsects; i++) {
451 sec = coff_sects[i];
452 if (!strcmp(sym, sec->name)) {
453 return;
455 r->symbol += 2;
458 saa_rewind(coff_syms);
459 for (uint32_t i = 0; i < coff_nsyms; i++) {
460 struct coff_Symbol *s = saa_rstruct(coff_syms);
461 r->symbol++;
462 if (s->strpos == -1 && !strcmp(sym, s->name)) {
463 return;
464 } else if (s->strpos != -1) {
465 int res;
466 char *symname;
468 symname = nasm_malloc(s->namlen + 1);
469 saa_fread(coff_strs, s->strpos-4, symname, s->namlen);
470 symname[s->namlen] = '\0';
471 res = strcmp(sym, symname);
472 nasm_free(symname);
473 if (!res)
474 return;
477 nasm_panic(0, "codeview: relocation for unregistered symbol: %s", sym);
480 static inline void section_write32(struct coff_Section *sect, uint32_t val)
482 saa_write32(sect->data, val);
483 sect->len += 4;
486 static inline void section_write16(struct coff_Section *sect, uint16_t val)
488 saa_write16(sect->data, val);
489 sect->len += 2;
492 static inline void section_write8(struct coff_Section *sect, uint8_t val)
494 saa_write8(sect->data, val);
495 sect->len++;
498 static inline void section_wbytes(struct coff_Section *sect, const void *buf,
499 size_t len)
501 saa_wbytes(sect->data, buf, len);
502 sect->len += len;
505 static void write_filename_table(struct coff_Section *const sect)
507 uint32_t field_length;
508 uint32_t tbl_off = 1; /* offset starts at 1 to skip NULL entry */
509 struct source_file *file;
511 nasm_assert(cv8_state.source_files != NULL);
512 nasm_assert(cv8_state.num_files > 0);
513 nasm_assert(cv8_state.total_filename_len > 0);
515 field_length = 1 + cv8_state.total_filename_len;
517 section_write32(sect, 0x000000F3);
518 section_write32(sect, field_length);
520 section_write8(sect, 0);
522 list_for_each(file, cv8_state.source_files) {
523 section_wbytes(sect, file->fullname, file->fullnamelen + 1);
524 file->filetbl_off = tbl_off;
525 tbl_off += file->fullnamelen + 1;
529 static void write_sourcefile_table(struct coff_Section *const sect)
531 const uint32_t entry_size = 4 + 2 + MD5_HASHBYTES + 2;
533 uint32_t field_length = 0;
534 uint32_t tbl_off = 0;
535 struct source_file *file;
537 field_length = entry_size * cv8_state.num_files;
539 section_write32(sect, 0x000000F4);
540 section_write32(sect, field_length);
542 list_for_each(file, cv8_state.source_files) {
543 nasm_assert(file->filetbl_off > 0);
544 section_write32(sect, file->filetbl_off);
545 section_write16(sect, 0x0110);
546 section_wbytes(sect, file->md5sum, MD5_HASHBYTES);
547 section_write16(sect, 0);
549 file->sourcetbl_off = tbl_off;
550 tbl_off += entry_size;
554 static void write_linenumber_table(struct coff_Section *const sect)
556 const uint32_t file_field_len = 12;
557 const uint32_t line_field_len = 8;
559 int i;
560 uint32_t field_length = 0;
561 size_t field_base;
562 struct source_file *file;
563 struct coff_Section *s;
565 for (i = 0; i < coff_nsects; i++) {
566 if (!strncmp(coff_sects[i]->name, ".text", 5))
567 break;
570 if (i == coff_nsects)
571 return;
572 s = coff_sects[i];
574 field_length = 12;
575 field_length += (cv8_state.num_files * file_field_len);
576 field_length += (cv8_state.total_lines * line_field_len);
578 section_write32(sect, 0x000000F2);
579 section_write32(sect, field_length);
581 field_base = sect->len;
582 section_write32(sect, 0); /* SECREL, updated by relocation */
583 section_write16(sect, 0); /* SECTION, updated by relocation*/
584 section_write16(sect, 0); /* pad */
585 section_write32(sect, s->len);
587 register_reloc(sect, ".text", field_base,
588 win64 ? IMAGE_REL_AMD64_SECREL : IMAGE_REL_I386_SECREL);
590 register_reloc(sect, ".text", field_base + 4,
591 win64 ? IMAGE_REL_AMD64_SECTION : IMAGE_REL_I386_SECTION);
593 list_for_each(file, cv8_state.source_files) {
594 struct linepair *li;
596 /* source mapping */
597 section_write32(sect, file->sourcetbl_off);
598 section_write32(sect, file->num_lines);
599 section_write32(sect, file_field_len + (file->num_lines * line_field_len));
601 /* the pairs */
602 saa_rewind(file->lines);
603 while ((li = saa_rstruct(file->lines))) {
604 section_write32(sect, li->file_offset);
605 section_write32(sect, li->linenumber |= 0x80000000);
610 static uint16_t write_symbolinfo_obj(struct coff_Section *sect)
612 uint16_t obj_len;
614 obj_len = 2 + 4 + cv8_state.outfile.namebytes;
616 section_write16(sect, obj_len);
617 section_write16(sect, 0x1101);
618 section_write32(sect, 0); /* ASM language */
619 section_wbytes(sect, cv8_state.outfile.name, cv8_state.outfile.namebytes);
621 return obj_len;
624 static uint16_t write_symbolinfo_properties(struct coff_Section *sect,
625 const char *const creator_str)
627 /* https://github.com/Microsoft/microsoft-pdb/blob/1d60e041/include/cvinfo.h#L3313 */
628 uint16_t creator_len;
630 creator_len = 2 + 4 + 2 + 3*2 + 3*2 + strlen(creator_str)+1 + 2;
632 section_write16(sect, creator_len);
633 section_write16(sect, 0x1116);
634 section_write32(sect, 3); /* language/flags */
635 if (win64)
636 section_write16(sect, 0x00D0); /* machine */
637 else if (win32)
638 section_write16(sect, 0x0006); /* machine */
639 else
640 nasm_assert(!"neither win32 nor win64 are set!");
641 section_write16(sect, 0); /* verFEMajor */
642 section_write16(sect, 0); /* verFEMinor */
643 section_write16(sect, 0); /* verFEBuild */
645 /* BinScope/WACK insist on version >= 8.0.50727 */
646 section_write16(sect, 8); /* verMajor */
647 section_write16(sect, 0); /* verMinor */
648 section_write16(sect, 50727); /* verBuild */
650 section_wbytes(sect, creator_str, strlen(creator_str)+1); /* verSt */
652 * normally there would be key/value pairs here, but they aren't
653 * necessary. They are terminated by 2B
655 section_write16(sect, 0);
657 return creator_len;
660 static uint16_t write_symbolinfo_symbols(struct coff_Section *sect)
662 uint16_t len = 0, field_len;
663 uint32_t field_base;
664 struct cv8_symbol *sym;
666 saa_rewind(cv8_state.symbols);
667 while ((sym = saa_rstruct(cv8_state.symbols))) {
668 switch (sym->type) {
669 case SYMTYPE_LDATA:
670 case SYMTYPE_GDATA:
671 field_len = 12 + strlen(sym->name) + 1;
672 len += field_len - 2;
673 section_write16(sect, field_len);
674 if (sym->type == SYMTYPE_LDATA)
675 section_write16(sect, 0x110C);
676 else
677 section_write16(sect, 0x110D);
678 section_write32(sect, sym->symtype);
680 field_base = sect->len;
681 section_write32(sect, 0); /* SECREL */
682 section_write16(sect, 0); /* SECTION */
683 break;
684 case SYMTYPE_PROC:
685 case SYMTYPE_CODE:
686 field_len = 9 + strlen(sym->name) + 1;
687 len += field_len - 2;
688 section_write16(sect, field_len);
689 section_write16(sect, 0x1105);
691 field_base = sect->len;
692 section_write32(sect, 0); /* SECREL */
693 section_write16(sect, 0); /* SECTION */
694 section_write8(sect, 0); /* FLAG */
695 break;
696 default:
697 nasm_assert(!"unknown symbol type");
700 section_wbytes(sect, sym->name, strlen(sym->name) + 1);
702 register_reloc(sect, sym->name, field_base,
703 win64 ? IMAGE_REL_AMD64_SECREL :
704 IMAGE_REL_I386_SECREL);
705 register_reloc(sect, sym->name, field_base + 4,
706 win64 ? IMAGE_REL_AMD64_SECTION :
707 IMAGE_REL_I386_SECTION);
710 return len;
713 static void write_symbolinfo_table(struct coff_Section *const sect)
715 static const char creator_str[] = "The Netwide Assembler " NASM_VER;
716 uint16_t obj_length, creator_length, sym_length;
717 uint32_t field_length = 0, out_len;
719 nasm_assert(cv8_state.outfile.namebytes);
721 /* signature, language, outfile NULL */
722 obj_length = 2 + 4 + cv8_state.outfile.namebytes;
723 creator_length = 2 + 4 + 2 + 3*2 + 3*2 + strlen(creator_str)+1 + 2;
725 sym_length = ( cv8_state.num_syms[SYMTYPE_CODE] * 7) +
726 ( cv8_state.num_syms[SYMTYPE_PROC] * 7) +
727 ( cv8_state.num_syms[SYMTYPE_LDATA] * 10) +
728 ( cv8_state.num_syms[SYMTYPE_GDATA] * 10) +
729 cv8_state.symbol_lengths;
731 field_length = 2 + obj_length +
732 2 + creator_length +
733 (4 * cv8_state.total_syms) + sym_length;
735 section_write32(sect, 0x000000F1);
736 section_write32(sect, field_length);
738 /* for sub fields, length preceeds type */
740 out_len = write_symbolinfo_obj(sect);
741 nasm_assert(out_len == obj_length);
743 out_len = write_symbolinfo_properties(sect, creator_str);
744 nasm_assert(out_len == creator_length);
746 out_len = write_symbolinfo_symbols(sect);
747 nasm_assert(out_len == sym_length);
750 static inline void align4_table(struct coff_Section *const sect)
752 unsigned diff;
753 uint32_t zero = 0;
754 struct SAA *data = sect->data;
756 if (data->wptr % 4 == 0)
757 return;
759 diff = 4 - (data->wptr % 4);
760 if (diff)
761 section_wbytes(sect, &zero, diff);
764 static void build_symbol_table(struct coff_Section *const sect)
766 section_write32(sect, 0x00000004);
768 write_filename_table(sect);
769 align4_table(sect);
770 write_sourcefile_table(sect);
771 align4_table(sect);
772 write_linenumber_table(sect);
773 align4_table(sect);
774 write_symbolinfo_table(sect);
775 align4_table(sect);
778 static void build_type_table(struct coff_Section *const sect)
780 uint16_t field_len;
781 struct cv8_symbol *sym;
783 section_write32(sect, 0x00000004);
785 saa_rewind(cv8_state.symbols);
786 while ((sym = saa_rstruct(cv8_state.symbols))) {
787 if (sym->type != SYMTYPE_PROC)
788 continue;
790 /* proc leaf */
792 field_len = 2 + 4 + 4 + 4 + 2;
793 section_write16(sect, field_len);
794 section_write16(sect, 0x1008); /* PROC type */
796 section_write32(sect, 0x00000003); /* return type */
797 section_write32(sect, 0); /* calling convention (default) */
798 section_write32(sect, sym->typeindex);
799 section_write16(sect, 0); /* # params */
801 /* arglist */
803 field_len = 2 + 4;
804 section_write16(sect, field_len);
805 section_write16(sect, 0x1201); /* ARGLIST */
806 section_write32(sect, 0); /*num params */