| ... | @@ -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 | } |
| 402 | | 402 | |
| 403 | fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 { | 403 | fn 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 | } |
| 410 | | 410 | |
| | 411 | const AllocateSegmentOpts = struct { |
| | 412 | addr: u64, // TODO find free VM space |
| | 413 | size: u64, |
| | 414 | alignment: u64, |
| | 415 | flags: u32 = elf.PF_R, |
| | 416 | }; |
| | 417 | |
| | 418 | fn 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 | |
| 411 | pub fn populateMissingMetadata(self: *Elf) !void { | 443 | pub 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 { |
| 438 | | 470 | |
| 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 | } |
| 454 | | 485 | |
| 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 | } |
| 475 | | 495 | |
| 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 something | 498 | // 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 | } |
| 500 | | 511 | |
| 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 GOT | 513 | // 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 | } |
| 523 | | 524 | |
| 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 GOT | 526 | // 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 | } |
| 546 | | 537 | |
| 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 GOT | 539 | // 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 | } |
| 566 | | 549 | |
| 567 | if (self.shstrtab_section_index == null) { | 550 | if (self.shstrtab_section_index == null) { |