| ... | ... | @@ -264,8 +264,8 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { |
| 264 | 264 | try self.populateMetadata(); |
| 265 | 265 | try self.parseInputFiles(files); |
| 266 | 266 | try self.resolveImports(); |
| 267 | | self.allocateTextSegment(); |
| 268 | | self.allocateDataSegment(); |
| 267 | try self.allocateTextSegment(); |
| 268 | try self.allocateDataSegment(); |
| 269 | 269 | self.allocateLinkeditSegment(); |
| 270 | 270 | try self.writeStubHelperCommon(); |
| 271 | 271 | try self.resolveSymbols(); |
| ... | ... | @@ -349,6 +349,7 @@ fn parseObjectFile(self: *Zld, object: *const Object) !void { |
| 349 | 349 | }; |
| 350 | 350 | } |
| 351 | 351 | const dest_sect = &seg.sections.items[res.entry.value.sect_index]; |
| 352 | dest_sect.@"align" = math.max(dest_sect.@"align", sect.@"align"); |
| 352 | 353 | dest_sect.size += sect.size; |
| 353 | 354 | seg.inner.filesize += sect.size; |
| 354 | 355 | } |
| ... | ... | @@ -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 | 446 | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 446 | 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 | 453 | // Set stubs and stub_helper sizes |
| 449 | 454 | const stubs = &seg.sections.items[self.stubs_section_index.?]; |
| 450 | 455 | const stub_helper = &seg.sections.items[self.stub_helper_section_index.?]; |
| ... | ... | @@ -462,19 +467,41 @@ fn allocateTextSegment(self: *Zld) void { |
| 462 | 467 | sizeofcmds += lc.cmdsize(); |
| 463 | 468 | } |
| 464 | 469 | |
| 465 | | self.allocateSegment( |
| 466 | | self.text_segment_cmd_index.?, |
| 467 | | 0, |
| 468 | | sizeofcmds, |
| 469 | | true, |
| 470 | | ); |
| 470 | try self.allocateSegment(self.text_segment_cmd_index.?, sizeofcmds); |
| 471 | |
| 472 | // Shift all sections to the back to minimize jump size between __TEXT and __DATA segments. |
| 473 | var min_alignment: u32 = 0; |
| 474 | for (seg.sections.items) |sect| { |
| 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 | 497 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 475 | 498 | const nonlazy = @intCast(u32, self.nonlazy_imports.items().len); |
| 476 | 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 | 505 | // Set got size |
| 479 | 506 | const got = &seg.sections.items[self.got_section_index.?]; |
| 480 | 507 | got.size += nonlazy * @sizeOf(u64); |
| ... | ... | @@ -485,50 +512,34 @@ fn allocateDataSegment(self: *Zld) void { |
| 485 | 512 | la_symbol_ptr.size += lazy * @sizeOf(u64); |
| 486 | 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; |
| 489 | | const offset = text_seg.inner.fileoff + text_seg.inner.filesize; |
| 490 | | self.allocateSegment(self.data_segment_cmd_index.?, offset, 0, false); |
| 515 | try self.allocateSegment(self.data_segment_cmd_index.?, 0); |
| 491 | 516 | } |
| 492 | 517 | |
| 493 | 518 | fn allocateLinkeditSegment(self: *Zld) void { |
| 519 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 494 | 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; |
| 496 | | self.allocateSegment(self.linkedit_segment_cmd_index.?, offset, 0, false); |
| 521 | seg.inner.fileoff = data_seg.inner.fileoff + data_seg.inner.filesize; |
| 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 | 526 | const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize; |
| 501 | 527 | const seg = &self.load_commands.items[index].Segment; |
| 502 | 528 | |
| 503 | | // Calculate segment size |
| 504 | | var total_size = start; |
| 505 | | for (seg.sections.items) |sect| { |
| 506 | | total_size += sect.size; |
| 507 | | } |
| 508 | | const aligned_size = mem.alignForwardGeneric(u64, total_size, self.page_size.?); |
| 509 | | seg.inner.vmaddr = base_vmaddr + offset; |
| 510 | | seg.inner.vmsize = aligned_size; |
| 511 | | seg.inner.fileoff = offset; |
| 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 | | } |
| 529 | // Allocate the sections according to their alignment at the beginning of the segment. |
| 530 | var start: u64 = offset; |
| 531 | for (seg.sections.items) |*sect| { |
| 532 | const alignment = try math.powi(u32, 2, sect.@"align"); |
| 533 | const start_aligned = mem.alignForwardGeneric(u64, start, alignment); |
| 534 | const end_aligned = mem.alignForwardGeneric(u64, start_aligned + sect.size, alignment); |
| 535 | sect.offset = @intCast(u32, seg.inner.fileoff + start_aligned); |
| 536 | sect.addr = seg.inner.vmaddr + start_aligned; |
| 537 | start = end_aligned; |
| 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 | 545 | fn writeStubHelperCommon(self: *Zld) !void { |