| ... | @@ -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 | } |
| 443 | | 444 | |
| 444 | fn allocateTextSegment(self: *Zld) void { | 445 | fn 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); |
| 447 | | 448 | |
| | 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 sizes | 453 | // 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 | } |
| 464 | | 469 | |
| 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 | } |
| 472 | | 495 | |
| 473 | fn allocateDataSegment(self: *Zld) void { | 496 | fn 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); |
| 477 | | 500 | |
| | 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 size | 505 | // 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? |
| 487 | | 514 | |
| 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 | } |
| 492 | | 517 | |
| 493 | fn allocateLinkeditSegment(self: *Zld) void { | 518 | fn 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 | } |
| 498 | | 524 | |
| 499 | fn allocateSegment(self: *Zld, index: u16, offset: u64, start: u64, reverse: bool) void { | 525 | fn 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; |
| 502 | | 528 | |
| 503 | // Calculate segment size | 529 | // 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 | } |
| 533 | | 544 | |
| 534 | fn writeStubHelperCommon(self: *Zld) !void { | 545 | fn writeStubHelperCommon(self: *Zld) !void { |