From 0d31ccdd5754b10fb27fcdc95ddd6c937ecec1bd Mon Sep 17 00:00:00 2001 From: Artem Pyanykh Date: Wed, 11 Sep 2019 20:30:24 +0100 Subject: [linker, macho] Don't map/allocate zero size sections and segments Zero size sections are common even during regular build on MacOS. For instance: ``` $ ar -xv libHSghc-prim-0.6.1.a longlong.o $ otool -l longlong.o longlong.o: Mach header magic cputype cpusubtype caps filetype ncmds sizeofcmds flags 0xfeedfacf 16777223 3 0x00 1 2 176 0x00002000 Load command 0 cmd LC_SEGMENT_64 cmdsize 152 segname vmaddr 0x0000000000000000 vmsize 0x0000000000000000 <-- segment size = 0 fileoff 208 filesize 0 maxprot 0x00000007 initprot 0x00000007 nsects 1 flags 0x0 Section sectname __text segname __TEXT addr 0x0000000000000000 size 0x0000000000000000 <-- section size = 0 offset 208 align 2^0 (1) reloff 0 nreloc 0 flags 0x80000000 reserved1 0 reserved2 0 cmd LC_BUILD_VERSION cmdsize 24 platform macos sdk 10.14 minos 10.14 ntools 0 ``` The issue of `mmap`ing 0 bytes was resolved in !1050, but the problem remained. These 0 size segments and sections were still allocated in object code, which lead to failed `ASSERT(size > 0)` in `addProddableBlock` further down the road. With this change zero size segments **and** sections are not mapped/allocated at all. Test plan: 1. Build statically linked GHC. 2. Run `ghc --interactive`. Observe that REPL loads successfully (which was not the case before). 3. Load several more compiled hs files into repl. No failures. --- rts/linker/MachO.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'rts') diff --git a/rts/linker/MachO.c b/rts/linker/MachO.c index 61c6d9d503..3da4f690f2 100644 --- a/rts/linker/MachO.c +++ b/rts/linker/MachO.c @@ -1091,6 +1091,11 @@ ocBuildSegments_MachO(ObjectCode *oc) for (int i = 0; i < oc->n_sections; i++) { MachOSection *macho = &oc->info->macho_sections[i]; + if (0 == macho->size) { + IF_DEBUG(linker, debugBelch("ocBuildSegments_MachO: found a zero length section, skipping\n")); + continue; + } + size_t alignment = 1 << macho->align; if (S_GB_ZEROFILL == (macho->flags & SECTION_TYPE)) { @@ -1118,17 +1123,22 @@ ocBuildSegments_MachO(ObjectCode *oc) if (n_rwSections > 0) { n_activeSegments++; } - if (n_gbZerofills >0) { + if (n_gbZerofills > 0) { n_activeSegments++; } // N.B. it's possible that there is nothing mappable in an object. In this - // case we avoid the mmap call since it would fail. See #16701. - if (size_compound > 0) { - mem = mmapForLinker(size_compound, MAP_ANON, -1, 0); - if (NULL == mem) return 0; + // case we avoid the mmap call and segment allocation/building since it will + // fail either here or further down the road, e.g. on size > 0 assert in + // addProddableBlock. See #16701. + if (0 == size_compound) { + IF_DEBUG(linker, debugBelch("ocBuildSegments_MachO: all segments are empty, skipping\n")); + return 1; } + mem = mmapForLinker(size_compound, MAP_ANON, -1, 0); + if (NULL == mem) return 0; + IF_DEBUG(linker, debugBelch("ocBuildSegments: allocating %d segments\n", n_activeSegments)); segments = (Segment*)stgCallocBytes(n_activeSegments, sizeof(Segment), "ocBuildSegments_MachO(segments)"); @@ -1182,6 +1192,11 @@ ocBuildSegments_MachO(ObjectCode *oc) i++) { MachOSection *macho = &oc->info->macho_sections[i]; + // Skip zero size sections here as well since there was no place + // allocated for them in Segment's sections_idx array + if (0 == macho->size) { + continue; + } if (S_GB_ZEROFILL == (macho->flags & SECTION_TYPE)) { gbZerofillSegment->sections_idx[gb++] = i; -- cgit v1.2.1