authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-02-28 11:36:39+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-03-17 19:59:13+01:00
log44ebf4863131fbf822caf6548a347abc52e5ce3b
tree674481cfea156cd2801df4095b266ec515d85344
parent7c22f4f85165965e5843a9f6bd800f0463f19122

zld: fix handling of section alignment


1 files changed, 55 insertions(+), 44 deletions(-)

src/link/MachO/Zld.zig+55-44
...@@ -264,8 +264,8 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {...@@ -264,8 +264,8 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {
264 try self.populateMetadata();264 try self.populateMetadata();
265 try self.parseInputFiles(files);265 try self.parseInputFiles(files);
266 try self.resolveImports();266 try self.resolveImports();
267 self.allocateTextSegment();267 try self.allocateTextSegment();
268 self.allocateDataSegment();268 try self.allocateDataSegment();
269 self.allocateLinkeditSegment();269 self.allocateLinkeditSegment();
270 try self.writeStubHelperCommon();270 try self.writeStubHelperCommon();
271 try self.resolveSymbols();271 try self.resolveSymbols();
...@@ -349,6 +349,7 @@ fn parseObjectFile(self: *Zld, object: *const Object) !void {...@@ -349,6 +349,7 @@ fn parseObjectFile(self: *Zld, object: *const Object) !void {
349 };349 };
350 }350 }
351 const dest_sect = &seg.sections.items[res.entry.value.sect_index];351 const dest_sect = &seg.sections.items[res.entry.value.sect_index];
352 dest_sect.@"align" = math.max(dest_sect.@"align", sect.@"align");
352 dest_sect.size += sect.size;353 dest_sect.size += sect.size;
353 seg.inner.filesize += sect.size;354 seg.inner.filesize += sect.size;
354 }355 }
...@@ -441,10 +442,14 @@ fn resolveImports(self: *Zld) !void {...@@ -441,10 +442,14 @@ fn resolveImports(self: *Zld) !void {
441 });442 });
442}443}
443444
444fn allocateTextSegment(self: *Zld) void {445fn allocateTextSegment(self: *Zld) !void {
445 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;446 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
446 const nexterns = @intCast(u32, self.lazy_imports.items().len);447 const nexterns = @intCast(u32, self.lazy_imports.items().len);
447448
449 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;
450 seg.inner.fileoff = 0;
451 seg.inner.vmaddr = base_vmaddr;
452
448 // Set stubs and stub_helper sizes453 // Set stubs and stub_helper sizes
449 const stubs = &seg.sections.items[self.stubs_section_index.?];454 const stubs = &seg.sections.items[self.stubs_section_index.?];
450 const stub_helper = &seg.sections.items[self.stub_helper_section_index.?];455 const stub_helper = &seg.sections.items[self.stub_helper_section_index.?];
...@@ -462,19 +467,41 @@ fn allocateTextSegment(self: *Zld) void {...@@ -462,19 +467,41 @@ fn allocateTextSegment(self: *Zld) void {
462 sizeofcmds += lc.cmdsize();467 sizeofcmds += lc.cmdsize();
463 }468 }
464469
465 self.allocateSegment(470 try self.allocateSegment(self.text_segment_cmd_index.?, sizeofcmds);
466 self.text_segment_cmd_index.?,471
467 0,472 // Shift all sections to the back to minimize jump size between __TEXT and __DATA segments.
468 sizeofcmds,473 var min_alignment: u32 = 0;
469 true,474 for (seg.sections.items) |sect| {
470 );475 const alignment = try math.powi(u32, 2, sect.@"align");
476 min_alignment = math.max(min_alignment, alignment);
477 }
478
479 assert(min_alignment > 0);
480 const last_sect_idx = seg.sections.items.len - 1;
481 const last_sect = seg.sections.items[last_sect_idx];
482 const shift: u32 = blk: {
483 const diff = seg.inner.filesize - last_sect.offset - last_sect.size;
484 const factor = @divTrunc(diff, min_alignment);
485 break :blk @intCast(u32, factor * min_alignment);
486 };
487
488 if (shift > 0) {
489 for (seg.sections.items) |*sect| {
490 sect.offset += shift;
491 sect.addr += shift;
492 }
493 }
471}494}
472495
473fn allocateDataSegment(self: *Zld) void {496fn allocateDataSegment(self: *Zld) !void {
474 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;497 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
475 const nonlazy = @intCast(u32, self.nonlazy_imports.items().len);498 const nonlazy = @intCast(u32, self.nonlazy_imports.items().len);
476 const lazy = @intCast(u32, self.lazy_imports.items().len);499 const lazy = @intCast(u32, self.lazy_imports.items().len);
477500
501 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
502 seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize;
503 seg.inner.vmaddr = text_seg.inner.vmaddr + text_seg.inner.vmsize;
504
478 // Set got size505 // Set got size
479 const got = &seg.sections.items[self.got_section_index.?];506 const got = &seg.sections.items[self.got_section_index.?];
480 got.size += nonlazy * @sizeOf(u64);507 got.size += nonlazy * @sizeOf(u64);
...@@ -485,50 +512,34 @@ fn allocateDataSegment(self: *Zld) void {...@@ -485,50 +512,34 @@ fn allocateDataSegment(self: *Zld) void {
485 la_symbol_ptr.size += lazy * @sizeOf(u64);512 la_symbol_ptr.size += lazy * @sizeOf(u64);
486 data.size += @sizeOf(u64); // TODO when do we need more?513 data.size += @sizeOf(u64); // TODO when do we need more?
487514
488 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;515 try self.allocateSegment(self.data_segment_cmd_index.?, 0);
489 const offset = text_seg.inner.fileoff + text_seg.inner.filesize;
490 self.allocateSegment(self.data_segment_cmd_index.?, offset, 0, false);
491}516}
492517
493fn allocateLinkeditSegment(self: *Zld) void {518fn allocateLinkeditSegment(self: *Zld) void {
519 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
494 const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;520 const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
495 const offset = data_seg.inner.fileoff + data_seg.inner.filesize;521 seg.inner.fileoff = data_seg.inner.fileoff + data_seg.inner.filesize;
496 self.allocateSegment(self.linkedit_segment_cmd_index.?, offset, 0, false);522 seg.inner.vmaddr = data_seg.inner.vmaddr + data_seg.inner.vmsize;
497}523}
498524
499fn allocateSegment(self: *Zld, index: u16, offset: u64, start: u64, reverse: bool) void {525fn allocateSegment(self: *Zld, index: u16, offset: u64) !void {
500 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;526 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;
501 const seg = &self.load_commands.items[index].Segment;527 const seg = &self.load_commands.items[index].Segment;
502528
503 // Calculate segment size529 // Allocate the sections according to their alignment at the beginning of the segment.
504 var total_size = start;530 var start: u64 = offset;
505 for (seg.sections.items) |sect| {531 for (seg.sections.items) |*sect| {
506 total_size += sect.size;532 const alignment = try math.powi(u32, 2, sect.@"align");
507 }533 const start_aligned = mem.alignForwardGeneric(u64, start, alignment);
508 const aligned_size = mem.alignForwardGeneric(u64, total_size, self.page_size.?);534 const end_aligned = mem.alignForwardGeneric(u64, start_aligned + sect.size, alignment);
509 seg.inner.vmaddr = base_vmaddr + offset;535 sect.offset = @intCast(u32, seg.inner.fileoff + start_aligned);
510 seg.inner.vmsize = aligned_size;536 sect.addr = seg.inner.vmaddr + start_aligned;
511 seg.inner.fileoff = offset;537 start = end_aligned;
512 seg.inner.filesize = aligned_size;
513
514 // Allocate section offsets
515 if (reverse) {
516 var end_off: u64 = seg.inner.fileoff + seg.inner.filesize;
517 var count: usize = seg.sections.items.len;
518 while (count > 0) : (count -= 1) {
519 const sec = &seg.sections.items[count - 1];
520 end_off -= mem.alignForwardGeneric(u64, sec.size, @alignOf(u128)); // TODO is 8-byte aligned correct?
521 sec.offset = @intCast(u32, end_off);
522 sec.addr = base_vmaddr + end_off;
523 }
524 } else {
525 var next_off: u64 = seg.inner.fileoff + start;
526 for (seg.sections.items) |*sect| {
527 sect.offset = @intCast(u32, next_off);
528 sect.addr = base_vmaddr + next_off;
529 next_off += mem.alignForwardGeneric(u64, sect.size, @alignOf(u128)); // TODO is 8-byte aligned correct?
530 }
531 }538 }
539
540 const seg_size_aligned = mem.alignForwardGeneric(u64, start, self.page_size.?);
541 seg.inner.filesize = seg_size_aligned;
542 seg.inner.vmsize = seg_size_aligned;
532}543}
533544
534fn writeStubHelperCommon(self: *Zld) !void {545fn writeStubHelperCommon(self: *Zld) !void {