diff --git a/macho/input-sections.cc b/macho/input-sections.cc index 2f14f1ab..42cf8706 100644 --- a/macho/input-sections.cc +++ b/macho/input-sections.cc @@ -13,7 +13,8 @@ std::ostream &operator<<(std::ostream &out, const InputSection &sec) { InputSection::InputSection(Context &ctx, ObjectFile &file, const MachSection &hdr) : file(file), hdr(hdr), osec(*OutputSection::get_instance(ctx, hdr.get_segname(), hdr.get_sectname())) { - contents = file.mf->get_contents().substr(hdr.offset, hdr.size); + if (hdr.type != S_ZEROFILL) + contents = file.mf->get_contents().substr(hdr.offset, hdr.size); subsections.push_back({*this, 0, (u32)contents.size(), (u32)hdr.addr}); } diff --git a/macho/main.cc b/macho/main.cc index 9c50b2a4..a4d70569 100644 --- a/macho/main.cc +++ b/macho/main.cc @@ -62,6 +62,9 @@ static void create_synthetic_chunks(Context &ctx) { ctx.data_seg.chunks.push_back(&ctx.lazy_symbol_ptr); ctx.data_seg.chunks.push_back(ctx.data); + if (!ctx.bss->members.empty()) + ctx.data_seg.chunks.push_back(ctx.bss); + ctx.linkedit_seg.chunks.push_back(&ctx.rebase); ctx.linkedit_seg.chunks.push_back(&ctx.bind); ctx.linkedit_seg.chunks.push_back(&ctx.lazy_bind); diff --git a/macho/mold.h b/macho/mold.h index f26404c3..533102df 100644 --- a/macho/mold.h +++ b/macho/mold.h @@ -127,6 +127,7 @@ std::ostream &operator<<(std::ostream &out, const InputSection &sec); class Subsection { public: std::string_view get_contents() { + assert(isec.hdr.type != S_ZEROFILL); return isec.contents.substr(input_offset, input_size); } @@ -583,8 +584,11 @@ struct Context { Context() { text = OutputSection::get_instance(*this, "__TEXT", "__text"); data = OutputSection::get_instance(*this, "__DATA", "__data"); + bss = OutputSection::get_instance(*this, "__DATA", "__bss"); cstring = OutputSection::get_instance(*this, "__TEXT", "__cstring"); common = OutputSection::get_instance(*this, "__TEXT", "__common"); + + bss->hdr.type = S_ZEROFILL; cstring->hdr.type = S_CSTRING_LITERALS; } @@ -660,6 +664,7 @@ struct Context { OutputSection *text = nullptr; OutputSection *data = nullptr; + OutputSection *bss = nullptr; OutputSection *cstring = nullptr; OutputSection *common = nullptr; diff --git a/macho/output-chunks.cc b/macho/output-chunks.cc index a68e7ced..585a912a 100644 --- a/macho/output-chunks.cc +++ b/macho/output-chunks.cc @@ -292,9 +292,11 @@ void OutputSection::copy_buf(Context &ctx) { u8 *buf = ctx.buf + hdr.offset; for (Subsection *subsec : members) { - std::string_view data = subsec->get_contents(); - memcpy(buf + subsec->output_offset, data.data(), data.size()); - subsec->apply_reloc(ctx, buf + subsec->output_offset); + if (subsec->isec.hdr.type != S_ZEROFILL) { + std::string_view data = subsec->get_contents(); + memcpy(buf + subsec->output_offset, data.data(), data.size()); + subsec->apply_reloc(ctx, buf + subsec->output_offset); + } } } @@ -310,19 +312,36 @@ void OutputSegment::set_offset(Context &ctx, i64 fileoff, u64 vmaddr) { cmd.fileoff = fileoff; cmd.vmaddr = vmaddr; - i64 offset = 0; + i64 i = 0; - for (Chunk *sec : chunks) { - offset = align_to(offset, 1 << sec->hdr.p2align); - sec->hdr.addr = vmaddr + offset; - sec->hdr.offset = fileoff + offset; - sec->compute_size(ctx); - offset += sec->hdr.size; + while (i < chunks.size() && chunks[i]->hdr.type != S_ZEROFILL) { + Chunk &sec = *chunks[i++]; + fileoff = align_to(fileoff, 1 << sec.hdr.p2align); + vmaddr = align_to(vmaddr, 1 << sec.hdr.p2align); + + sec.hdr.offset = fileoff; + sec.hdr.addr = vmaddr; + + sec.compute_size(ctx); + fileoff += sec.hdr.size; + vmaddr += sec.hdr.size; } - cmd.vmsize = align_to(offset, PAGE_SIZE); - cmd.filesize = - (this == ctx.segments.back()) ? offset : align_to(offset, PAGE_SIZE); + while (i < chunks.size()) { + Chunk &sec = *chunks[i++]; + assert(sec.hdr.type == S_ZEROFILL); + vmaddr = align_to(vmaddr, 1 << sec.hdr.p2align); + sec.hdr.addr = vmaddr; + sec.compute_size(ctx); + vmaddr += sec.hdr.size; + } + + cmd.vmsize = align_to(vmaddr - cmd.vmaddr, PAGE_SIZE); + + if (this == ctx.segments.back()) + cmd.filesize = fileoff - cmd.fileoff; + else + cmd.filesize = align_to(fileoff - cmd.fileoff, PAGE_SIZE); } void OutputSegment::copy_buf(Context &ctx) { diff --git a/test/macho/bss.sh b/test/macho/bss.sh new file mode 100755 index 00000000..c4322509 --- /dev/null +++ b/test/macho/bss.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -e +cd $(dirname $0) +mold=`pwd`/../../ld64.mold +echo -n "Testing $(basename -s .sh $0) ... " +t=$(pwd)/../../out/test/macho/$(basename -s .sh $0) +mkdir -p $t + +cat < + +static int foo[100]; + +int main() { + foo[1] = 5; + printf("%d %d %p\n", foo[0], foo[1], foo); +} +EOF + +clang -fuse-ld=$mold -o $t/exe $t/a.o +$t/exe | grep -q '^0 5 ' + +echo OK