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 {
400400 return min_pos - start;
401401}
402402
403fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 {
403fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 {
404404 var start: u64 = 0;
405405 while (self.detectAllocCollision(start, object_size)) |item_end| {
406406 start = mem.alignForward(u64, item_end, min_alignment);
......@@ -408,6 +408,38 @@ fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 {
408408 return start;
409409}
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
411443pub fn populateMissingMetadata(self: *Elf) !void {
412444 const gpa = self.base.allocator;
413445 const small_ptr = switch (self.ptr_width) {
......@@ -438,7 +470,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {
438470
439471 if (self.phdr_table_load_index == null) {
440472 self.phdr_table_load_index = @intCast(self.phdrs.items.len);
441 // TODO Same as for GOT
442473 try self.phdrs.append(gpa, .{
443474 .p_type = elf.PT_LOAD,
444475 .p_offset = 0,
......@@ -453,115 +484,67 @@ pub fn populateMissingMetadata(self: *Elf) !void {
453484 }
454485
455486 if (self.phdr_load_re_index == null) {
456 self.phdr_load_re_index = @intCast(self.phdrs.items.len);
457 const file_size = self.base.options.program_code_size_hint;
458 const p_align = self.page_size;
459 const off = self.findFreeSpace(file_size, p_align);
460 log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size });
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,
487 self.phdr_load_re_index = try self.allocateSegment(.{
488 .addr = self.defaultEntryAddress(),
489 .size = self.base.options.program_code_size_hint,
490 .alignment = self.page_size,
491 .flags = elf.PF_X | elf.PF_R | elf.PF_W,
471492 });
472493 self.entry_addr = null;
473 self.phdr_table_dirty = true;
474494 }
475495
476496 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 });
484497 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
485498 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
486499 // else in virtual memory.
487 const got_addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0x4000000 else 0x8000;
488 try self.phdrs.append(gpa, .{
489 .p_type = elf.PT_LOAD,
490 .p_offset = off,
491 .p_filesz = file_size,
492 .p_vaddr = got_addr,
493 .p_paddr = got_addr,
494 .p_memsz = file_size,
495 .p_align = p_align,
496 .p_flags = elf.PF_R | elf.PF_W,
500 const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x4000000 else 0x8000;
501 // We really only need ptr alignment but since we are using PROGBITS, linux requires
502 // page align.
503 const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
504 self.phdr_got_index = try self.allocateSegment(.{
505 .addr = addr,
506 .size = @as(u64, ptr_size) * self.base.options.symbol_count_hint,
507 .alignment = alignment,
508 .flags = elf.PF_R | elf.PF_W,
497509 });
498 self.phdr_table_dirty = true;
499510 }
500511
501512 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 });
509513 // TODO Same as for GOT
510 const rodata_addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0xc000000 else 0xa000;
511 try self.phdrs.append(gpa, .{
512 .p_type = elf.PT_LOAD,
513 .p_offset = off,
514 .p_filesz = file_size,
515 .p_vaddr = rodata_addr,
516 .p_paddr = rodata_addr,
517 .p_memsz = file_size,
518 .p_align = p_align,
519 .p_flags = elf.PF_R | elf.PF_W,
514 const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0xc000000 else 0xa000;
515 // Same reason as for GOT
516 const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
517 self.phdr_load_ro_index = try self.allocateSegment(.{
518 .addr = addr,
519 .size = 1024,
520 .alignment = alignment,
521 .flags = elf.PF_R | elf.PF_W,
520522 });
521 self.phdr_table_dirty = true;
522523 }
523524
524525 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 });
532526 // TODO Same as for GOT
533 const rwdata_addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0x10000000 else 0xc000;
534 try self.phdrs.append(gpa, .{
535 .p_type = elf.PT_LOAD,
536 .p_offset = off,
537 .p_filesz = file_size,
538 .p_vaddr = rwdata_addr,
539 .p_paddr = rwdata_addr,
540 .p_memsz = file_size,
541 .p_align = p_align,
542 .p_flags = elf.PF_R | elf.PF_W,
527 const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x10000000 else 0xc000;
528 // Same reason as for GOT
529 const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
530 self.phdr_load_rw_index = try self.allocateSegment(.{
531 .addr = addr,
532 .size = 1024,
533 .alignment = alignment,
534 .flags = elf.PF_R | elf.PF_W,
543535 });
544 self.phdr_table_dirty = true;
545536 }
546537
547538 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 });
552539 // TODO Same as for GOT
553 const addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0x14000000 else 0xf000;
554 try self.phdrs.append(gpa, .{
555 .p_type = elf.PT_LOAD,
556 .p_offset = off,
557 .p_filesz = 0,
558 .p_vaddr = addr,
559 .p_paddr = addr,
560 .p_memsz = 0,
561 .p_align = p_align,
562 .p_flags = elf.PF_R | elf.PF_W,
540 const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x14000000 else 0xf000;
541 const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
542 self.phdr_load_zerofill_index = try self.allocateSegment(.{
543 .addr = addr,
544 .size = 0,
545 .alignment = alignment,
546 .flags = elf.PF_R | elf.PF_W,
563547 });
564 self.phdr_table_dirty = true;
565548 }
566549
567550 if (self.shstrtab_section_index == null) {