commit b8dcd8a7bdd3f2ce01756fd8ce410d64786424de
parent 11895ae0ea7cc7f8fc16664bae5d2fff4aa87c1d
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Thu, 4 Jun 2026 16:41:30 -0700
coff: emit PE exception directory metadata
Diffstat:
1 file changed, 24 insertions(+), 5 deletions(-)
diff --git a/src/obj/coff/link.c b/src/obj/coff/link.c
@@ -118,8 +118,9 @@ typedef enum CoffBucket {
COFF_BUCKET_DATA = 3,
COFF_BUCKET_TLS = 4,
COFF_BUCKET_BSS = 5,
- COFF_BUCKET_RELOC = 6,
- COFF_NBUCKETS = 7,
+ COFF_BUCKET_PDATA = 6,
+ COFF_BUCKET_RELOC = 7,
+ COFF_NBUCKETS = 8,
} CoffBucket;
/* IMAGE_TLS_DIRECTORY64 wire size: u64*4 + u32*2 = 40 bytes. */
@@ -160,7 +161,12 @@ static void coff_write_zeroes(Writer* w, u64 n) {
* code resolve against the merged TLS image, not against .data.
* Everything else partitions on SF_EXEC / SF_WRITE plus the SSEM_NOBITS
* bit for .bss. */
-static CoffBucket coff_bucket_for(const LinkSection* ls) {
+static CoffBucket coff_bucket_for(Compiler* c, const LinkSection* ls) {
+ if (ls->name) {
+ Slice nm = pool_slice(c->global, ls->name);
+ if (nm.s && nm.len >= 6u && memcmp(nm.s, ".pdata", 6u) == 0)
+ return COFF_BUCKET_PDATA;
+ }
if (ls->flags & SF_EXEC) return COFF_BUCKET_TEXT;
if (ls->flags & SF_TLS) return COFF_BUCKET_TLS;
if (ls->sem == SSEM_NOBITS) return COFF_BUCKET_BSS;
@@ -901,7 +907,7 @@ static void coff_place_section(LinkImage* img, CoffSection out[COFF_NBUCKETS],
u32 bucket_cap[COFF_NBUCKETS],
const LinkSection* ls) {
Heap* heap = img->heap;
- CoffBucket b2 = coff_bucket_for(ls);
+ CoffBucket b2 = coff_bucket_for(img->c, ls);
u32 align = ls->align ? ls->align : 1u;
u64 cur = bucket_cur[b2];
cur = ALIGN_UP(cur, (u64)align);
@@ -997,6 +1003,10 @@ static void coff_build_buckets(LinkImage* img, CoffSection out[COFF_NBUCKETS],
IMAGE_SCN_MEM_READ |
IMAGE_SCN_MEM_WRITE;
out[COFF_BUCKET_BSS].has_file_bytes = 0;
+ out[COFF_BUCKET_PDATA].name = ".pdata";
+ out[COFF_BUCKET_PDATA].characteristics =
+ IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
+ out[COFF_BUCKET_PDATA].has_file_bytes = 1;
out[COFF_BUCKET_RELOC].name = ".reloc";
out[COFF_BUCKET_RELOC].characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA |
IMAGE_SCN_MEM_READ |
@@ -1400,7 +1410,11 @@ static void coff_write_optional_header(Writer* w, u32 entry_rva,
out[COFF_BUCKET_TEXT].in_image ? out[COFF_BUCKET_TEXT].size_raw : 0;
u32 size_init =
(out[COFF_BUCKET_RDATA].in_image ? out[COFF_BUCKET_RDATA].size_raw : 0) +
- (out[COFF_BUCKET_DATA].in_image ? out[COFF_BUCKET_DATA].size_raw : 0);
+ (out[COFF_BUCKET_IDATA].in_image ? out[COFF_BUCKET_IDATA].size_raw : 0) +
+ (out[COFF_BUCKET_DATA].in_image ? out[COFF_BUCKET_DATA].size_raw : 0) +
+ (out[COFF_BUCKET_TLS].in_image ? out[COFF_BUCKET_TLS].size_raw : 0) +
+ (out[COFF_BUCKET_PDATA].in_image ? out[COFF_BUCKET_PDATA].size_raw : 0) +
+ (out[COFF_BUCKET_RELOC].in_image ? out[COFF_BUCKET_RELOC].size_raw : 0);
u32 size_uninit =
out[COFF_BUCKET_BSS].in_image ? out[COFF_BUCKET_BSS].size : 0;
coff_wr_u32(w, size_code);
@@ -1433,6 +1447,7 @@ static void coff_write_optional_header(Writer* w, u32 entry_rva,
coff_wr_u32(w, (u32)PE_NUM_DATA_DIRS);
/* DataDirectory[16]. Populated entries:
* [1] IMPORT — descriptor table RVA + total descriptor bytes
+ * [3] EXCEPTION — .pdata runtime-function table
* [5] BASERELOC — when PIE and .reloc is in the image
* [12] IAT — first IAT block RVA + sum of per-DLL IAT sizes
* Everything else stays zero. */
@@ -1442,6 +1457,10 @@ static void coff_write_optional_header(Writer* w, u32 entry_rva,
if (i == IMAGE_DIRECTORY_ENTRY_IMPORT && has_idata) {
coff_wr_u32(w, out[COFF_BUCKET_IDATA].rva + it->desc_off);
coff_wr_u32(w, it->desc_size);
+ } else if (i == IMAGE_DIRECTORY_ENTRY_EXCEPTION &&
+ out[COFF_BUCKET_PDATA].in_image) {
+ coff_wr_u32(w, out[COFF_BUCKET_PDATA].rva);
+ coff_wr_u32(w, out[COFF_BUCKET_PDATA].size);
} else if (i == IMAGE_DIRECTORY_ENTRY_IAT && has_idata) {
coff_wr_u32(w, out[COFF_BUCKET_IDATA].rva + it->iat_base);
coff_wr_u32(w, it->iat_total);