From 9ae8559cbc323787be5869b5d952af1eb2533f5e Mon Sep 17 00:00:00 2001 From: Peter0x44 Date: Sun, 15 Mar 2026 22:14:36 +0000 Subject: [PATCH 1/2] Add LTO support --- Dockerfile | 18 +- src/gcc-bigobj-coff-lto.patch | 658 ++++++++++++++++++++++++++++++++++ 2 files changed, 667 insertions(+), 9 deletions(-) create mode 100644 src/gcc-bigobj-coff-lto.patch diff --git a/Dockerfile b/Dockerfile index 9ebb4c3..afbf2f6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -250,7 +250,7 @@ RUN cat $PREFIX/src/gcc-*.patch | patch -d/dl/gcc -p1 \ --disable-libstdcxx-verbose \ --disable-dependency-tracking \ --disable-nls \ - --disable-lto \ + --enable-lto \ --disable-multilib \ CFLAGS_FOR_TARGET="-O2" \ CXXFLAGS_FOR_TARGET="-O2" \ @@ -359,6 +359,12 @@ RUN /dl/mpc/configure \ && make -j$(nproc) \ && make install +COPY --from=dl-zstd /dl/zstd/ /dl/zstd/ +WORKDIR /dl/zstd/lib +RUN make -j$(nproc) CC=$ARCH-gcc AR=$ARCH-ar CFLAGS="-O2" libzstd.a \ + && cp libzstd.a /deps/lib/ \ + && cp zstd.h zstd_errors.h zdict.h /deps/include/ + WORKDIR /mingw-headers RUN /dl/mingw/mingw-w64-headers/configure \ --prefix=$PREFIX \ @@ -411,13 +417,14 @@ RUN echo 'BEGIN {print "pecoff"}' \ --with-gmp=/deps \ --with-mpc=/deps \ --with-mpfr=/deps \ + --with-zstd=/deps \ --enable-languages=c,c++,fortran \ --enable-libgomp \ --enable-threads=posix \ --enable-version-specific-runtime-libs \ --disable-libstdcxx-verbose \ --disable-dependency-tracking \ - --disable-lto \ + --enable-lto \ --disable-multilib \ --disable-nls \ --disable-win32-registry \ @@ -645,13 +652,6 @@ RUN cat $PREFIX/src/ctags-*.patch | patch -p1 \ && cp ctags.exe /out/bin/ FROM cross AS build-zstd -COPY --from=dl-zstd /dl/ /dl/ - -WORKDIR /dl/zstd/lib -RUN make -j$(nproc) CC=$ARCH-gcc AR=$ARCH-ar CFLAGS="-O2" libzstd.a \ - && cp libzstd.a /deps/lib/ \ - && cp zstd.h zstd_errors.h zdict.h /deps/include/ - WORKDIR /dl/zstd RUN make -j$(nproc) -C programs zstd \ CC=$ARCH-gcc CFLAGS="-O2" LDFLAGS="-s" EXT=.exe \ diff --git a/src/gcc-bigobj-coff-lto.patch b/src/gcc-bigobj-coff-lto.patch new file mode 100644 index 0000000..b5fb369 --- /dev/null +++ b/src/gcc-bigobj-coff-lto.patch @@ -0,0 +1,658 @@ +From f401c2b735c106d7b5b3f2e69358e520c780ad4c Mon Sep 17 00:00:00 2001 +From: Peter Damianov +Date: Thu, 6 Nov 2025 00:14:44 +0000 +Subject: [PATCH] libiberty: Add BigObj COFF support for LTO on Windows targets + [PR122472] + +This patch adds support for the BigObj COFF object file format to libiberty's +simple-object-coff.c. BigObj extends regular COFF to support a 32-bit section +count. + +BigObj differs from COFF in a few ways: + +* A different header structure +* 32-bit section counts instead of 16-bit +* 32-bit symbol section numbers instead of 16-bit +* 20-byte symbols instead of 18-byte symbols + (due to the extended section numbers) + +For a more detailed summary, read my blog post on this subject: +https://peter0x44.github.io/posts/bigobj_format_explained/ + +libiberty/ChangeLog: + + PR target/122472 + * simple-object-coff.c (struct external_filehdr_bigobj): New + structure for BigObj file header. + (bigobj_magic): New constant for BigObj magic bytes. + (struct external_syment_bigobj): New structure for BigObj + 20-byte symbol table entries. + (union external_auxent_bigobj): New union for BigObj 20-byte + auxiliary symbol entries. + (struct simple_object_coff_read): Add is_bigobj flag and make + nscns 32-bit to support both formats. + (struct simple_object_coff_attributes): Add is_bigobj flag. + (simple_object_coff_match): Add BigObj format detection. + (simple_object_coff_read_strtab): Use format-specific symbol + size when calculating string table offset. + (simple_object_coff_attributes_merge): Check is_bigobj flag. + (simple_object_coff_write_filehdr_bigobj): New function. + (simple_object_coff_write_to_file): Add logic for writing + BigObj vs regular COFF format with appropriate symbol + and auxiliary entry structures. + +Signed-off-by: Peter Damianov +Signed-off-by: Jonathan Yong <10walls@gmail.com> +--- + libiberty/simple-object-coff.c | 459 +++++++++++++++++++++++++++------ + 1 file changed, 379 insertions(+), 80 deletions(-) + +diff --git a/libiberty/simple-object-coff.c b/libiberty/simple-object-coff.c +index 922477f7445..7f3b4628d6e 100644 +--- a/libiberty/simple-object-coff.c ++++ b/libiberty/simple-object-coff.c +@@ -57,6 +57,32 @@ struct external_filehdr + unsigned char f_flags[2]; /* flags */ + }; + ++/* BigObj COFF file header. */ ++ ++struct external_filehdr_bigobj ++{ ++ unsigned char sig1[2]; /* Must be 0x0000 */ ++ unsigned char sig2[2]; /* Must be 0xFFFF */ ++ unsigned char version[2]; /* Version, currently 2 */ ++ unsigned char machine[2]; /* Machine type */ ++ unsigned char timdat[4]; /* time & date stamp */ ++ unsigned char classid[16]; /* Magic GUID that identifies BigObj format */ ++ unsigned char sizeofdata[4]; /* Size of data (unused, set to 0) */ ++ unsigned char flags[4]; /* Flags (unused, set to 0) */ ++ unsigned char metadatasize[4]; /* Metadata size (unused, set to 0) */ ++ unsigned char metadataoffset[4]; /* Metadata offset (unused, set to 0) */ ++ unsigned char nscns[4]; /* number of sections (32-bit!) */ ++ unsigned char symptr[4]; /* file pointer to symtab */ ++ unsigned char nsyms[4]; /* number of symtab entries */ ++}; ++ ++/* The BigObj magic GUID (ClassID). */ ++static const unsigned char bigobj_magic[16] = ++{ ++ 0xC7, 0xA1, 0xBA, 0xD1, 0xEE, 0xBA, 0xA9, 0x4B, ++ 0xAF, 0x20, 0xFA, 0xF6, 0x6A, 0xA4, 0xDC, 0xB8 ++}; ++ + /* Bits for filehdr f_flags field. */ + + #define F_EXEC (0x0002) +@@ -119,6 +145,28 @@ struct external_syment + unsigned char e_numaux[1]; + }; + ++/* BigObj COFF symbol table entry (20 bytes instead of 18). */ ++ ++struct external_syment_bigobj ++{ ++ union ++ { ++ unsigned char e_name[E_SYMNMLEN]; ++ ++ struct ++ { ++ unsigned char e_zeroes[4]; ++ unsigned char e_offset[4]; ++ } e; ++ } e; ++ ++ unsigned char e_value[4]; ++ unsigned char e_scnum[4]; /* 32-bit section number! */ ++ unsigned char e_type[2]; ++ unsigned char e_sclass[1]; ++ unsigned char e_numaux[1]; ++}; ++ + /* Length allowed for filename in aux sym format 4. */ + + #define E_FILNMLEN 18 +@@ -149,6 +197,33 @@ union external_auxent + } x_scn; + }; + ++/* BigObj auxiliary symbol (20 bytes to match symbol size). */ ++ ++union external_auxent_bigobj ++{ ++ /* Aux sym format 4: file. */ ++ union ++ { ++ char x_fname[E_FILNMLEN]; ++ struct ++ { ++ unsigned char x_zeroes[4]; ++ unsigned char x_offset[4]; ++ } x_n; ++ } x_file; ++ /* Aux sym format 5: section. */ ++ struct ++ { ++ unsigned char x_scnlen[4]; /* section length */ ++ unsigned char x_nreloc[2]; /* # relocation entries */ ++ unsigned char x_nlinno[2]; /* # line numbers */ ++ unsigned char x_checksum[4]; /* section COMDAT checksum */ ++ unsigned char x_associated[2]; /* COMDAT assoc section index */ ++ unsigned char x_comdat[1]; /* COMDAT selection number */ ++ unsigned char x_pad[3]; /* Padding to 20 bytes */ ++ } x_scn; ++}; ++ + /* Symbol-related constants. */ + + #define IMAGE_SYM_DEBUG (-2) +@@ -168,8 +243,10 @@ struct simple_object_coff_read + unsigned short magic; + /* Whether the file is big-endian. */ + unsigned char is_big_endian; ++ /* Whether this is BigObj format. */ ++ unsigned char is_bigobj; + /* Number of sections. */ +- unsigned short nscns; ++ unsigned int nscns; + /* File offset of symbol table. */ + off_t symptr; + /* Number of symbol table entries. */ +@@ -188,6 +265,8 @@ struct simple_object_coff_attributes + unsigned short magic; + /* Whether the file is big-endian. */ + unsigned char is_big_endian; ++ /* Whether this is BigObj format. */ ++ unsigned char is_bigobj; + /* Flags. */ + unsigned short flags; + }; +@@ -240,10 +319,12 @@ simple_object_coff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], + int is_big_endian; + unsigned short (*fetch_16) (const unsigned char *); + unsigned int (*fetch_32) (const unsigned char *); +- unsigned char hdrbuf[sizeof (struct external_filehdr)]; ++ unsigned char hdrbuf[sizeof (struct external_filehdr_bigobj)]; + unsigned short flags; + struct simple_object_coff_read *ocr; ++ unsigned short sig1, sig2; + ++ /* Try regular COFF first. */ + c = sizeof (coff_magic) / sizeof (coff_magic[0]); + magic_big = simple_object_fetch_big_16 (header); + magic_little = simple_object_fetch_little_16 (header); +@@ -254,12 +335,64 @@ simple_object_coff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], + : coff_magic[i].magic == magic_little) + break; + } +- if (i >= c) ++ ++ /* Check for BigObj if regular COFF didn't match. */ ++ sig1 = simple_object_fetch_little_16 (header); ++ sig2 = simple_object_fetch_little_16 (header + 2); ++ ++ if (i >= c && (sig1 != 0 || sig2 != 0xFFFF)) + { ++ /* Not regular COFF and not BigObj. */ + *errmsg = NULL; + *err = 0; + return NULL; + } ++ ++ if (sig1 == 0 && sig2 == 0xFFFF) ++ { ++ /* This looks like BigObj. Verify the ClassID. */ ++ unsigned char bigobj_hdrbuf[sizeof (struct external_filehdr_bigobj)]; ++ ++ if (!simple_object_internal_read (descriptor, offset, bigobj_hdrbuf, ++ sizeof bigobj_hdrbuf, errmsg, err)) ++ return NULL; ++ ++ if (memcmp (bigobj_hdrbuf + offsetof (struct external_filehdr_bigobj, ++ classid), ++ bigobj_magic, 16) != 0) ++ { ++ *errmsg = NULL; ++ *err = 0; ++ return NULL; ++ } ++ ++ /* BigObj is always little-endian. */ ++ is_big_endian = 0; ++ ++ ocr = XNEW (struct simple_object_coff_read); ++ ocr->magic = simple_object_fetch_little_16 ++ (bigobj_hdrbuf ++ + offsetof (struct external_filehdr_bigobj, machine)); ++ ocr->is_big_endian = 0; ++ ocr->is_bigobj = 1; ++ ocr->nscns = simple_object_fetch_little_32 ++ (bigobj_hdrbuf ++ + offsetof (struct external_filehdr_bigobj, nscns)); ++ ocr->symptr = simple_object_fetch_little_32 ++ (bigobj_hdrbuf ++ + offsetof (struct external_filehdr_bigobj, symptr)); ++ ocr->nsyms = simple_object_fetch_little_32 ++ (bigobj_hdrbuf ++ + offsetof (struct external_filehdr_bigobj, nsyms)); ++ ocr->flags = simple_object_fetch_little_32 ++ (bigobj_hdrbuf ++ + offsetof (struct external_filehdr_bigobj, flags)); ++ ocr->scnhdr_offset = sizeof (struct external_filehdr_bigobj); ++ ++ return (void *) ocr; ++ } ++ ++ /* Regular COFF. */ + is_big_endian = coff_magic[i].is_big_endian; + + magic = is_big_endian ? magic_big : magic_little; +@@ -270,7 +403,7 @@ simple_object_coff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], + ? simple_object_fetch_big_32 + : simple_object_fetch_little_32); + +- if (!simple_object_internal_read (descriptor, offset, hdrbuf, sizeof hdrbuf, ++ if (!simple_object_internal_read (descriptor, offset, hdrbuf, sizeof (struct external_filehdr), + errmsg, err)) + return NULL; + +@@ -285,6 +418,7 @@ simple_object_coff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], + ocr = XNEW (struct simple_object_coff_read); + ocr->magic = magic; + ocr->is_big_endian = is_big_endian; ++ ocr->is_bigobj = 0; + ocr->nscns = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_nscns)); + ocr->symptr = fetch_32 (hdrbuf + + offsetof (struct external_filehdr, f_symptr)); +@@ -309,9 +443,13 @@ simple_object_coff_read_strtab (simple_object_read *sobj, size_t *strtab_size, + unsigned char strsizebuf[4]; + size_t strsize; + char *strtab; ++ size_t sym_size; ++ ++ /* Symbol size depends on format. */ ++ sym_size = ocr->is_bigobj ? sizeof (struct external_syment_bigobj) ++ : sizeof (struct external_syment); + +- strtab_offset = sobj->offset + ocr->symptr +- + ocr->nsyms * sizeof (struct external_syment); ++ strtab_offset = sobj->offset + ocr->symptr + ocr->nsyms * sym_size; + if (!simple_object_internal_read (sobj->descriptor, strtab_offset, + strsizebuf, 4, errmsg, err)) + return NULL; +@@ -444,6 +582,7 @@ simple_object_coff_fetch_attributes (simple_object_read *sobj, + ret = XNEW (struct simple_object_coff_attributes); + ret->magic = ocr->magic; + ret->is_big_endian = ocr->is_big_endian; ++ ret->is_bigobj = ocr->is_bigobj; + ret->flags = ocr->flags; + return ret; + } +@@ -466,7 +605,9 @@ simple_object_coff_attributes_merge (void *todata, void *fromdata, int *err) + struct simple_object_coff_attributes *from = + (struct simple_object_coff_attributes *) fromdata; + +- if (to->magic != from->magic || to->is_big_endian != from->is_big_endian) ++ if (to->magic != from->magic ++ || to->is_big_endian != from->is_big_endian ++ || to->is_bigobj != from->is_bigobj) + { + *err = 0; + return "COFF object format mismatch"; +@@ -500,6 +641,52 @@ simple_object_coff_start_write (void *attributes_data, + return ret; + } + ++/* Write out a BigObj COFF filehdr. */ ++ ++static int ++simple_object_coff_write_filehdr_bigobj (simple_object_write *sobj, ++ int descriptor, ++ unsigned int nscns, ++ size_t symtab_offset, ++ unsigned int nsyms, ++ const char **errmsg, int *err) ++{ ++ struct simple_object_coff_attributes *attrs = ++ (struct simple_object_coff_attributes *) sobj->data; ++ unsigned char hdrbuf[sizeof (struct external_filehdr_bigobj)]; ++ unsigned char *hdr; ++ void (*set_16) (unsigned char *, unsigned short); ++ void (*set_32) (unsigned char *, unsigned int); ++ ++ hdr = &hdrbuf[0]; ++ ++ /* BigObj is always little-endian. */ ++ set_16 = simple_object_set_little_16; ++ set_32 = simple_object_set_little_32; ++ ++ memset (hdr, 0, sizeof (struct external_filehdr_bigobj)); ++ ++ /* Set BigObj signatures. */ ++ set_16 (hdr + offsetof (struct external_filehdr_bigobj, sig1), 0); ++ set_16 (hdr + offsetof (struct external_filehdr_bigobj, sig2), 0xFFFF); ++ set_16 (hdr + offsetof (struct external_filehdr_bigobj, version), 2); ++ set_16 (hdr + offsetof (struct external_filehdr_bigobj, machine), ++ attrs->magic); ++ /* timdat left as zero. */ ++ /* Copy ClassID. */ ++ memcpy (hdr + offsetof (struct external_filehdr_bigobj, classid), ++ bigobj_magic, 16); ++ /* sizeofdata, flags, metadatasize, metadataoffset left as zero. */ ++ set_32 (hdr + offsetof (struct external_filehdr_bigobj, nscns), nscns); ++ set_32 (hdr + offsetof (struct external_filehdr_bigobj, symptr), ++ symtab_offset); ++ set_32 (hdr + offsetof (struct external_filehdr_bigobj, nsyms), nsyms); ++ ++ return simple_object_internal_write (descriptor, 0, hdrbuf, ++ sizeof (struct external_filehdr_bigobj), ++ errmsg, err); ++} ++ + /* Write out a COFF filehdr. */ + + static int +@@ -618,14 +805,16 @@ simple_object_coff_write_to_file (simple_object_write *sobj, int descriptor, + what 'gas' uses when told to assemble from stdin. */ + const char *source_filename = "fake"; + size_t sflen; +- union +- { +- struct external_syment sym; +- union external_auxent aux; +- } syms[2]; ++ size_t symsize; + void (*set_16) (unsigned char *, unsigned short); + void (*set_32) (unsigned char *, unsigned int); + ++ /* Determine symbol size based on format. */ ++ if (attrs->is_bigobj) ++ symsize = sizeof (struct external_syment_bigobj); ++ else ++ symsize = sizeof (struct external_syment); ++ + set_16 = (attrs->is_big_endian + ? simple_object_set_big_16 + : simple_object_set_little_16); +@@ -637,7 +826,10 @@ simple_object_coff_write_to_file (simple_object_write *sobj, int descriptor, + for (section = sobj->sections; section != NULL; section = section->next) + ++nscns; + +- scnhdr_offset = sizeof (struct external_filehdr); ++ if (attrs->is_bigobj) ++ scnhdr_offset = sizeof (struct external_filehdr_bigobj); ++ else ++ scnhdr_offset = sizeof (struct external_filehdr); + offset = scnhdr_offset + nscns * sizeof (struct external_scnhdr); + name_offset = 4; + for (section = sobj->sections; section != NULL; section = section->next) +@@ -693,91 +885,198 @@ simple_object_coff_write_to_file (simple_object_write *sobj, int descriptor, + symtab_offset = offset; + /* Advance across space reserved for symbol table to locate + start of string table. */ +- offset += nsyms * sizeof (struct external_syment); ++ offset += nsyms * symsize; + + /* Write out file symbol. */ +- memset (&syms[0], 0, sizeof (syms)); +- strcpy ((char *)&syms[0].sym.e.e_name[0], ".file"); +- set_16 (&syms[0].sym.e_scnum[0], IMAGE_SYM_DEBUG); +- set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE); +- syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_FILE; +- syms[0].sym.e_numaux[0] = 1; +- /* The name need not be nul-terminated if it fits into the x_fname field +- directly, but must be if it has to be placed into the string table. */ +- sflen = strlen (source_filename); +- if (sflen <= E_FILNMLEN) +- memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen); +- else ++ if (attrs->is_bigobj) + { +- set_32 (&syms[1].aux.x_file.x_n.x_offset[0], name_offset); +- if (!simple_object_internal_write (descriptor, offset + name_offset, +- ((const unsigned char *) +- source_filename), +- sflen + 1, &errmsg, err)) ++ union ++ { ++ struct external_syment_bigobj sym; ++ union external_auxent_bigobj aux; ++ } syms[2]; ++ ++ memset (&syms[0], 0, sizeof (syms)); ++ strcpy ((char *)&syms[0].sym.e.e_name[0], ".file"); ++ set_32 (&syms[0].sym.e_scnum[0], IMAGE_SYM_DEBUG); ++ set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE); ++ syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_FILE; ++ syms[0].sym.e_numaux[0] = 1; ++ /* The name need not be nul-terminated if it fits into the x_fname field ++ directly, but must be if it has to be placed into the string table. */ ++ sflen = strlen (source_filename); ++ if (sflen <= E_FILNMLEN) ++ memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen); ++ else ++ { ++ set_32 (&syms[1].aux.x_file.x_n.x_offset[0], name_offset); ++ if (!simple_object_internal_write (descriptor, offset + name_offset, ++ ((const unsigned char *) ++ source_filename), ++ sflen + 1, &errmsg, err)) ++ return errmsg; ++ name_offset += strlen (source_filename) + 1; ++ } ++ if (!simple_object_internal_write (descriptor, symtab_offset, ++ (const unsigned char *) &syms[0], ++ sizeof (syms), &errmsg, err)) + return errmsg; +- name_offset += strlen (source_filename) + 1; +- } +- if (!simple_object_internal_write (descriptor, symtab_offset, +- (const unsigned char *) &syms[0], +- sizeof (syms), &errmsg, err)) +- return errmsg; +- +- /* Write the string table length, followed by the strings and section +- symbols in step with each other. */ +- set_32 (strsizebuf, name_offset); +- if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4, +- &errmsg, err)) +- return errmsg; + +- name_offset = 4; +- secsym_offset = symtab_offset + sizeof (syms); +- memset (&syms[0], 0, sizeof (syms)); +- set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE); +- syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_STATIC; +- syms[0].sym.e_numaux[0] = 1; +- secnum = 1; ++ /* Write the string table length, followed by the strings and section ++ symbols in step with each other. */ ++ set_32 (strsizebuf, name_offset); ++ if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4, ++ &errmsg, err)) ++ return errmsg; + +- for (section = sobj->sections; section != NULL; section = section->next) +- { +- size_t namelen; +- size_t scnsize; +- struct simple_object_write_section_buffer *buffer; ++ name_offset = 4; ++ secsym_offset = symtab_offset + sizeof (syms); ++ memset (&syms[0], 0, sizeof (syms)); ++ set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE); ++ syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_STATIC; ++ syms[0].sym.e_numaux[0] = 1; ++ secnum = 1; + +- namelen = strlen (section->name); +- set_16 (&syms[0].sym.e_scnum[0], secnum++); +- scnsize = 0; +- for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) +- scnsize += buffer->size; +- set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize); +- if (namelen > SCNNMLEN) ++ for (section = sobj->sections; section != NULL; section = section->next) + { +- set_32 (&syms[0].sym.e.e.e_zeroes[0], 0); +- set_32 (&syms[0].sym.e.e.e_offset[0], name_offset); +- if (!simple_object_internal_write (descriptor, offset + name_offset, +- ((const unsigned char *) +- section->name), +- namelen + 1, &errmsg, err)) ++ size_t namelen; ++ size_t scnsize; ++ struct simple_object_write_section_buffer *buffer; ++ ++ namelen = strlen (section->name); ++ set_32 (&syms[0].sym.e_scnum[0], secnum++); ++ scnsize = 0; ++ for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) ++ scnsize += buffer->size; ++ set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize); ++ if (namelen > SCNNMLEN) ++ { ++ set_32 (&syms[0].sym.e.e.e_zeroes[0], 0); ++ set_32 (&syms[0].sym.e.e.e_offset[0], name_offset); ++ if (!simple_object_internal_write (descriptor, offset + name_offset, ++ ((const unsigned char *) ++ section->name), ++ namelen + 1, &errmsg, err)) ++ return errmsg; ++ name_offset += namelen + 1; ++ } ++ else ++ { ++ memcpy (&syms[0].sym.e.e_name[0], section->name, ++ strlen (section->name)); ++ memset (&syms[0].sym.e.e_name[strlen (section->name)], 0, ++ E_SYMNMLEN - strlen (section->name)); ++ } ++ ++ if (!simple_object_internal_write (descriptor, secsym_offset, ++ (const unsigned char *) &syms[0], ++ sizeof (syms), &errmsg, err)) + return errmsg; +- name_offset += namelen + 1; ++ secsym_offset += sizeof (syms); + } ++ } ++ else ++ { ++ /* Regular COFF. */ ++ union ++ { ++ struct external_syment sym; ++ union external_auxent aux; ++ } syms[2]; ++ ++ memset (&syms[0], 0, sizeof (syms)); ++ strcpy ((char *)&syms[0].sym.e.e_name[0], ".file"); ++ set_16 (&syms[0].sym.e_scnum[0], IMAGE_SYM_DEBUG); ++ set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE); ++ syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_FILE; ++ syms[0].sym.e_numaux[0] = 1; ++ /* The name need not be nul-terminated if it fits into the x_fname field ++ directly, but must be if it has to be placed into the string table. */ ++ sflen = strlen (source_filename); ++ if (sflen <= E_FILNMLEN) ++ memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen); + else + { +- memcpy (&syms[0].sym.e.e_name[0], section->name, +- strlen (section->name)); +- memset (&syms[0].sym.e.e_name[strlen (section->name)], 0, +- E_SYMNMLEN - strlen (section->name)); ++ set_32 (&syms[1].aux.x_file.x_n.x_offset[0], name_offset); ++ if (!simple_object_internal_write (descriptor, offset + name_offset, ++ ((const unsigned char *) ++ source_filename), ++ sflen + 1, &errmsg, err)) ++ return errmsg; ++ name_offset += strlen (source_filename) + 1; + } +- +- if (!simple_object_internal_write (descriptor, secsym_offset, ++ if (!simple_object_internal_write (descriptor, symtab_offset, + (const unsigned char *) &syms[0], + sizeof (syms), &errmsg, err)) + return errmsg; +- secsym_offset += sizeof (syms); ++ ++ /* Write the string table length, followed by the strings and section ++ symbols in step with each other. */ ++ set_32 (strsizebuf, name_offset); ++ if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4, ++ &errmsg, err)) ++ return errmsg; ++ ++ name_offset = 4; ++ secsym_offset = symtab_offset + sizeof (syms); ++ memset (&syms[0], 0, sizeof (syms)); ++ set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE); ++ syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_STATIC; ++ syms[0].sym.e_numaux[0] = 1; ++ secnum = 1; ++ ++ for (section = sobj->sections; section != NULL; section = section->next) ++ { ++ size_t namelen; ++ size_t scnsize; ++ struct simple_object_write_section_buffer *buffer; ++ ++ namelen = strlen (section->name); ++ set_16 (&syms[0].sym.e_scnum[0], secnum++); ++ scnsize = 0; ++ for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) ++ scnsize += buffer->size; ++ set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize); ++ if (namelen > SCNNMLEN) ++ { ++ set_32 (&syms[0].sym.e.e.e_zeroes[0], 0); ++ set_32 (&syms[0].sym.e.e.e_offset[0], name_offset); ++ if (!simple_object_internal_write (descriptor, offset + name_offset, ++ ((const unsigned char *) ++ section->name), ++ namelen + 1, &errmsg, err)) ++ return errmsg; ++ name_offset += namelen + 1; ++ } ++ else ++ { ++ memcpy (&syms[0].sym.e.e_name[0], section->name, ++ strlen (section->name)); ++ memset (&syms[0].sym.e.e_name[strlen (section->name)], 0, ++ E_SYMNMLEN - strlen (section->name)); ++ } ++ ++ if (!simple_object_internal_write (descriptor, secsym_offset, ++ (const unsigned char *) &syms[0], ++ sizeof (syms), &errmsg, err)) ++ return errmsg; ++ secsym_offset += sizeof (syms); ++ } + } + +- if (!simple_object_coff_write_filehdr (sobj, descriptor, nscns, +- symtab_offset, nsyms, &errmsg, err)) +- return errmsg; ++ if (attrs->is_bigobj) ++ { ++ if (!simple_object_coff_write_filehdr_bigobj (sobj, descriptor, nscns, ++ symtab_offset, nsyms, ++ &errmsg, err)) ++ return errmsg; ++ } ++ else ++ { ++ if (!simple_object_coff_write_filehdr (sobj, descriptor, nscns, ++ symtab_offset, nsyms, &errmsg, err)) ++ return errmsg; ++ } + + return NULL; + } +-- +2.52.0 + From 08e66c0e0d92cfd8ead8d86d3ae720bd563bebef Mon Sep 17 00:00:00 2001 From: Peter0x44 Date: Wed, 25 Mar 2026 00:56:54 +0000 Subject: [PATCH 2/2] Add patch to fix emitted undefined reference to _pei386_runtime_relocator --- ...untime-reloacator-undefinedreference.patch | 66 +++++++++++++++++++ src/gcc-bigobj-coff-lto.patch | 54 --------------- 2 files changed, 66 insertions(+), 54 deletions(-) create mode 100644 src/binutils-pei386-runtime-reloacator-undefinedreference.patch diff --git a/src/binutils-pei386-runtime-reloacator-undefinedreference.patch b/src/binutils-pei386-runtime-reloacator-undefinedreference.patch new file mode 100644 index 0000000..3cc54aa --- /dev/null +++ b/src/binutils-pei386-runtime-reloacator-undefinedreference.patch @@ -0,0 +1,66 @@ +--- a/ld/emultempl/pe.em ++++ b/ld/emultempl/pe.em +@@ -1248,6 +1248,18 @@ make_runtime_ref (void) + } + } + ++static bool ++have_plugin_claimed_input (void) ++{ ++ lang_input_statement_type *f; ++ ++ for (f = (void *) file_chain.head; f != NULL; f = f->next) ++ if (f->flags.claimed) ++ return true; ++ ++ return false; ++} ++ + static bool + pr_sym (struct bfd_hash_entry *h, void *inf ATTRIBUTE_UNUSED) + { +@@ -1457,7 +1469,9 @@ gld${EMULATION_NAME}_before_plugin_all_symbols_read (void) + { + #ifdef DLL_SUPPORT + if (link_info.lto_plugin_active +- && link_info.pei386_auto_import) ++ && link_info.pei386_auto_import ++ && link_info.pei386_runtime_pseudo_reloc != 0 ++ && have_plugin_claimed_input ()) + make_runtime_ref (); + #endif + } +diff --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em +index 280949b6e51..a72caf97de9 100644 +--- a/ld/emultempl/pep.em ++++ b/ld/emultempl/pep.em +@@ -1254,6 +1254,18 @@ make_runtime_ref (void) + } + } + ++static bool ++have_plugin_claimed_input (void) ++{ ++ lang_input_statement_type *f; ++ ++ for (f = (void *) file_chain.head; f != NULL; f = f->next) ++ if (f->flags.claimed) ++ return true; ++ ++ return false; ++} ++ + static bool + pr_sym (struct bfd_hash_entry *h, void *inf ATTRIBUTE_UNUSED) + { +@@ -1464,7 +1476,9 @@ gld${EMULATION_NAME}_before_plugin_all_symbols_read (void) + { + #ifdef DLL_SUPPORT + if (link_info.lto_plugin_active +- && link_info.pei386_auto_import) /* -1=warn or 1=enable */ ++ && link_info.pei386_auto_import /* -1=warn or 1=enable */ ++ && link_info.pei386_runtime_pseudo_reloc != 0 ++ && have_plugin_claimed_input ()) + make_runtime_ref (); + #endif + } diff --git a/src/gcc-bigobj-coff-lto.patch b/src/gcc-bigobj-coff-lto.patch index b5fb369..50634c2 100644 --- a/src/gcc-bigobj-coff-lto.patch +++ b/src/gcc-bigobj-coff-lto.patch @@ -1,54 +1,3 @@ -From f401c2b735c106d7b5b3f2e69358e520c780ad4c Mon Sep 17 00:00:00 2001 -From: Peter Damianov -Date: Thu, 6 Nov 2025 00:14:44 +0000 -Subject: [PATCH] libiberty: Add BigObj COFF support for LTO on Windows targets - [PR122472] - -This patch adds support for the BigObj COFF object file format to libiberty's -simple-object-coff.c. BigObj extends regular COFF to support a 32-bit section -count. - -BigObj differs from COFF in a few ways: - -* A different header structure -* 32-bit section counts instead of 16-bit -* 32-bit symbol section numbers instead of 16-bit -* 20-byte symbols instead of 18-byte symbols - (due to the extended section numbers) - -For a more detailed summary, read my blog post on this subject: -https://peter0x44.github.io/posts/bigobj_format_explained/ - -libiberty/ChangeLog: - - PR target/122472 - * simple-object-coff.c (struct external_filehdr_bigobj): New - structure for BigObj file header. - (bigobj_magic): New constant for BigObj magic bytes. - (struct external_syment_bigobj): New structure for BigObj - 20-byte symbol table entries. - (union external_auxent_bigobj): New union for BigObj 20-byte - auxiliary symbol entries. - (struct simple_object_coff_read): Add is_bigobj flag and make - nscns 32-bit to support both formats. - (struct simple_object_coff_attributes): Add is_bigobj flag. - (simple_object_coff_match): Add BigObj format detection. - (simple_object_coff_read_strtab): Use format-specific symbol - size when calculating string table offset. - (simple_object_coff_attributes_merge): Check is_bigobj flag. - (simple_object_coff_write_filehdr_bigobj): New function. - (simple_object_coff_write_to_file): Add logic for writing - BigObj vs regular COFF format with appropriate symbol - and auxiliary entry structures. - -Signed-off-by: Peter Damianov -Signed-off-by: Jonathan Yong <10walls@gmail.com> ---- - libiberty/simple-object-coff.c | 459 +++++++++++++++++++++++++++------ - 1 file changed, 379 insertions(+), 80 deletions(-) - -diff --git a/libiberty/simple-object-coff.c b/libiberty/simple-object-coff.c -index 922477f7445..7f3b4628d6e 100644 --- a/libiberty/simple-object-coff.c +++ b/libiberty/simple-object-coff.c @@ -57,6 +57,32 @@ struct external_filehdr @@ -653,6 +602,3 @@ index 922477f7445..7f3b4628d6e 100644 return NULL; } --- -2.52.0 -