authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-22 23:17:06+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-23 17:14:27+02:00
log9f05cb318b77c18c312592cba52c782d70f2432f
tree641b2ec534bb9047e2ff88973b7e3d8171811971
parentd9c5a26cfb992b0951c80b80298dba2d690c7639

elf: put logic for allocating load segments in a helper


1 files changed, 70 insertions(+), 87 deletions(-)

src/link/Elf.zig+70-87
...@@ -400,7 +400,7 @@ fn allocatedVirtualSize(self: *Elf, start: u64) u64 {...@@ -400,7 +400,7 @@ fn allocatedVirtualSize(self: *Elf, start: u64) u64 {
400 return min_pos - start;400 return min_pos - start;
401}401}
402402
403fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 {403fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 {
404 var start: u64 = 0;404 var start: u64 = 0;
405 while (self.detectAllocCollision(start, object_size)) |item_end| {405 while (self.detectAllocCollision(start, object_size)) |item_end| {
406 start = mem.alignForward(u64, item_end, min_alignment);406 start = mem.alignForward(u64, item_end, min_alignment);
...@@ -408,6 +408,38 @@ fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 {...@@ -408,6 +408,38 @@ fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 {
408 return start;408 return start;
409}409}
410410
411const AllocateSegmentOpts = struct {
412 addr: u64, // TODO find free VM space
413 size: u64,
414 alignment: u64,
415 flags: u32 = elf.PF_R,
416};
417
418fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) !u16 {
419 const index = @as(u16, @intCast(self.phdrs.items.len));
420 try self.phdrs.ensureUnusedCapacity(self.base.allocator, 1);
421 const off = self.findFreeSpace(opts.size, opts.alignment);
422 log.debug("found PHDR {c}{c}{c} free space 0x{x} to 0x{x}", .{
423 if (opts.flags & elf.PF_R != 0) @as(u8, 'R') else '_',
424 if (opts.flags & elf.PF_W != 0) @as(u8, 'W') else '_',
425 if (opts.flags & elf.PF_X != 0) @as(u8, 'X') else '_',
426 off,
427 off + opts.size,
428 });
429 self.phdrs.appendAssumeCapacity(.{
430 .p_type = elf.PT_LOAD,
431 .p_offset = off,
432 .p_filesz = opts.size,
433 .p_vaddr = opts.addr,
434 .p_paddr = opts.addr,
435 .p_memsz = opts.size,
436 .p_align = opts.alignment,
437 .p_flags = opts.flags,
438 });
439 self.phdr_table_dirty = true;
440 return index;
441}
442
411pub fn populateMissingMetadata(self: *Elf) !void {443pub fn populateMissingMetadata(self: *Elf) !void {
412 const gpa = self.base.allocator;444 const gpa = self.base.allocator;
413 const small_ptr = switch (self.ptr_width) {445 const small_ptr = switch (self.ptr_width) {
...@@ -438,7 +470,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -438,7 +470,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {
438470
439 if (self.phdr_table_load_index == null) {471 if (self.phdr_table_load_index == null) {
440 self.phdr_table_load_index = @intCast(self.phdrs.items.len);472 self.phdr_table_load_index = @intCast(self.phdrs.items.len);
441 // TODO Same as for GOT
442 try self.phdrs.append(gpa, .{473 try self.phdrs.append(gpa, .{
443 .p_type = elf.PT_LOAD,474 .p_type = elf.PT_LOAD,
444 .p_offset = 0,475 .p_offset = 0,
...@@ -453,115 +484,67 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -453,115 +484,67 @@ pub fn populateMissingMetadata(self: *Elf) !void {
453 }484 }
454485
455 if (self.phdr_load_re_index == null) {486 if (self.phdr_load_re_index == null) {
456 self.phdr_load_re_index = @intCast(self.phdrs.items.len);487 self.phdr_load_re_index = try self.allocateSegment(.{
457 const file_size = self.base.options.program_code_size_hint;488 .addr = self.defaultEntryAddress(),
458 const p_align = self.page_size;489 .size = self.base.options.program_code_size_hint,
459 const off = self.findFreeSpace(file_size, p_align);490 .alignment = self.page_size,
460 log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size });491 .flags = elf.PF_X | elf.PF_R | elf.PF_W,
461 const entry_addr = self.defaultEntryAddress();
462 try self.phdrs.append(gpa, .{
463 .p_type = elf.PT_LOAD,
464 .p_offset = off,
465 .p_filesz = file_size,
466 .p_vaddr = entry_addr,
467 .p_paddr = entry_addr,
468 .p_memsz = file_size,
469 .p_align = p_align,
470 .p_flags = elf.PF_X | elf.PF_R | elf.PF_W,
471 });492 });
472 self.entry_addr = null;493 self.entry_addr = null;
473 self.phdr_table_dirty = true;
474 }494 }
475495
476 if (self.phdr_got_index == null) {496 if (self.phdr_got_index == null) {
477 self.phdr_got_index = @intCast(self.phdrs.items.len);
478 const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint;
479 // We really only need ptr alignment but since we are using PROGBITS, linux requires
480 // page align.
481 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
482 const off = self.findFreeSpace(file_size, p_align);
483 log.debug("found PT_LOAD GOT free space 0x{x} to 0x{x}", .{ off, off + file_size });
484 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.497 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
485 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something498 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
486 // else in virtual memory.499 // else in virtual memory.
487 const got_addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0x4000000 else 0x8000;500 const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x4000000 else 0x8000;
488 try self.phdrs.append(gpa, .{501 // We really only need ptr alignment but since we are using PROGBITS, linux requires
489 .p_type = elf.PT_LOAD,502 // page align.
490 .p_offset = off,503 const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
491 .p_filesz = file_size,504 self.phdr_got_index = try self.allocateSegment(.{
492 .p_vaddr = got_addr,505 .addr = addr,
493 .p_paddr = got_addr,506 .size = @as(u64, ptr_size) * self.base.options.symbol_count_hint,
494 .p_memsz = file_size,507 .alignment = alignment,
495 .p_align = p_align,508 .flags = elf.PF_R | elf.PF_W,
496 .p_flags = elf.PF_R | elf.PF_W,
497 });509 });
498 self.phdr_table_dirty = true;
499 }510 }
500511
501 if (self.phdr_load_ro_index == null) {512 if (self.phdr_load_ro_index == null) {
502 self.phdr_load_ro_index = @intCast(self.phdrs.items.len);
503 // TODO Find a hint about how much data need to be in rodata ?
504 const file_size = 1024;
505 // Same reason as for GOT
506 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
507 const off = self.findFreeSpace(file_size, p_align);
508 log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}", .{ off, off + file_size });
509 // TODO Same as for GOT513 // TODO Same as for GOT
510 const rodata_addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0xc000000 else 0xa000;514 const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0xc000000 else 0xa000;
511 try self.phdrs.append(gpa, .{515 // Same reason as for GOT
512 .p_type = elf.PT_LOAD,516 const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
513 .p_offset = off,517 self.phdr_load_ro_index = try self.allocateSegment(.{
514 .p_filesz = file_size,518 .addr = addr,
515 .p_vaddr = rodata_addr,519 .size = 1024,
516 .p_paddr = rodata_addr,520 .alignment = alignment,
517 .p_memsz = file_size,521 .flags = elf.PF_R | elf.PF_W,
518 .p_align = p_align,
519 .p_flags = elf.PF_R | elf.PF_W,
520 });522 });
521 self.phdr_table_dirty = true;
522 }523 }
523524
524 if (self.phdr_load_rw_index == null) {525 if (self.phdr_load_rw_index == null) {
525 self.phdr_load_rw_index = @intCast(self.phdrs.items.len);
526 // TODO Find a hint about how much data need to be in data ?
527 const file_size = 1024;
528 // Same reason as for GOT
529 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
530 const off = self.findFreeSpace(file_size, p_align);
531 log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}", .{ off, off + file_size });
532 // TODO Same as for GOT526 // TODO Same as for GOT
533 const rwdata_addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0x10000000 else 0xc000;527 const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x10000000 else 0xc000;
534 try self.phdrs.append(gpa, .{528 // Same reason as for GOT
535 .p_type = elf.PT_LOAD,529 const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
536 .p_offset = off,530 self.phdr_load_rw_index = try self.allocateSegment(.{
537 .p_filesz = file_size,531 .addr = addr,
538 .p_vaddr = rwdata_addr,532 .size = 1024,
539 .p_paddr = rwdata_addr,533 .alignment = alignment,
540 .p_memsz = file_size,534 .flags = elf.PF_R | elf.PF_W,
541 .p_align = p_align,
542 .p_flags = elf.PF_R | elf.PF_W,
543 });535 });
544 self.phdr_table_dirty = true;
545 }536 }
546537
547 if (self.phdr_load_zerofill_index == null) {538 if (self.phdr_load_zerofill_index == null) {
548 self.phdr_load_zerofill_index = @intCast(self.phdrs.items.len);
549 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
550 const off = self.phdrs.items[self.phdr_load_rw_index.?].p_offset;
551 log.debug("found PT_LOAD zerofill free space 0x{x} to 0x{x}", .{ off, off });
552 // TODO Same as for GOT539 // TODO Same as for GOT
553 const addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0x14000000 else 0xf000;540 const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x14000000 else 0xf000;
554 try self.phdrs.append(gpa, .{541 const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
555 .p_type = elf.PT_LOAD,542 self.phdr_load_zerofill_index = try self.allocateSegment(.{
556 .p_offset = off,543 .addr = addr,
557 .p_filesz = 0,544 .size = 0,
558 .p_vaddr = addr,545 .alignment = alignment,
559 .p_paddr = addr,546 .flags = elf.PF_R | elf.PF_W,
560 .p_memsz = 0,
561 .p_align = p_align,
562 .p_flags = elf.PF_R | elf.PF_W,
563 });547 });
564 self.phdr_table_dirty = true;
565 }548 }
566549
567 if (self.shstrtab_section_index == null) {550 if (self.shstrtab_section_index == null) {