| ... | ... | @@ -400,7 +400,7 @@ fn allocatedVirtualSize(self: *Elf, start: u64) u64 { |
| 400 | 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 | 404 | var start: u64 = 0; |
| 405 | 405 | while (self.detectAllocCollision(start, object_size)) |item_end| { |
| 406 | 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 | 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 | 443 | pub fn populateMissingMetadata(self: *Elf) !void { |
| 412 | 444 | const gpa = self.base.allocator; |
| 413 | 445 | const small_ptr = switch (self.ptr_width) { |
| ... | ... | @@ -438,7 +470,6 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 438 | 470 | |
| 439 | 471 | if (self.phdr_table_load_index == null) { |
| 440 | 472 | self.phdr_table_load_index = @intCast(self.phdrs.items.len); |
| 441 | | // TODO Same as for GOT |
| 442 | 473 | try self.phdrs.append(gpa, .{ |
| 443 | 474 | .p_type = elf.PT_LOAD, |
| 444 | 475 | .p_offset = 0, |
| ... | ... | @@ -453,115 +484,67 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 453 | 484 | } |
| 454 | 485 | |
| 455 | 486 | 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, |
| 471 | 492 | }); |
| 472 | 493 | self.entry_addr = null; |
| 473 | | self.phdr_table_dirty = true; |
| 474 | 494 | } |
| 475 | 495 | |
| 476 | 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 | 497 | // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at. |
| 485 | 498 | // we'll need to re-use that function anyway, in case the GOT grows and overlaps something |
| 486 | 499 | // 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, |
| 497 | 509 | }); |
| 498 | | self.phdr_table_dirty = true; |
| 499 | 510 | } |
| 500 | 511 | |
| 501 | 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 | 513 | // 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, |
| 520 | 522 | }); |
| 521 | | self.phdr_table_dirty = true; |
| 522 | 523 | } |
| 523 | 524 | |
| 524 | 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 | 526 | // 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, |
| 543 | 535 | }); |
| 544 | | self.phdr_table_dirty = true; |
| 545 | 536 | } |
| 546 | 537 | |
| 547 | 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 | 539 | // 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, |
| 563 | 547 | }); |
| 564 | | self.phdr_table_dirty = true; |
| 565 | 548 | } |
| 566 | 549 | |
| 567 | 550 | if (self.shstrtab_section_index == null) { |