| ... | @@ -373,9 +373,8 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { | ... | @@ -373,9 +373,8 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { |
| 373 | return null; | 373 | return null; |
| 374 | } | 374 | } |
| 375 | | 375 | |
| 376 | pub fn allocatedSize(self: *Elf, start: u64) u64 { | 376 | fn allocatedSize(self: *Elf, start: u64) u64 { |
| 377 | if (start == 0) | 377 | if (start == 0) return 0; |
| 378 | return 0; | | |
| 379 | var min_pos: u64 = std.math.maxInt(u64); | 378 | var min_pos: u64 = std.math.maxInt(u64); |
| 380 | if (self.shdr_table_offset) |off| { | 379 | if (self.shdr_table_offset) |off| { |
| 381 | if (off > start and off < min_pos) min_pos = off; | 380 | if (off > start and off < min_pos) min_pos = off; |
| ... | @@ -391,7 +390,17 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 { | ... | @@ -391,7 +390,17 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 { |
| 391 | return min_pos - start; | 390 | return min_pos - start; |
| 392 | } | 391 | } |
| 393 | | 392 | |
| 394 | pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 { | 393 | fn allocatedVirtualSize(self: *Elf, start: u64) u64 { |
| | 394 | if (start == 0) return 0; |
| | 395 | var min_pos: u64 = std.math.maxInt(u64); |
| | 396 | for (self.phdrs.items) |phdr| { |
| | 397 | if (phdr.p_vaddr <= start) continue; |
| | 398 | if (phdr.p_vaddr < min_pos) min_pos = phdr.p_vaddr; |
| | 399 | } |
| | 400 | return min_pos - start; |
| | 401 | } |
| | 402 | |
| | 403 | fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 { |
| 395 | var start: u64 = 0; | 404 | var start: u64 = 0; |
| 396 | while (self.detectAllocCollision(start, object_size)) |item_end| { | 405 | while (self.detectAllocCollision(start, object_size)) |item_end| { |
| 397 | start = mem.alignForward(u64, item_end, min_alignment); | 406 | start = mem.alignForward(u64, item_end, min_alignment); |
| ... | @@ -399,6 +408,113 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 { | ... | @@ -399,6 +408,113 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 { |
| 399 | return start; | 408 | return start; |
| 400 | } | 409 | } |
| 401 | | 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) error{OutOfMemory}!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("allocating phdr({d})({c}{c}{c}) from 0x{x} to 0x{x} (0x{x} - 0x{x})", .{ |
| | 423 | index, |
| | 424 | if (opts.flags & elf.PF_R != 0) @as(u8, 'R') else '_', |
| | 425 | if (opts.flags & elf.PF_W != 0) @as(u8, 'W') else '_', |
| | 426 | if (opts.flags & elf.PF_X != 0) @as(u8, 'X') else '_', |
| | 427 | off, |
| | 428 | off + opts.size, |
| | 429 | opts.addr, |
| | 430 | opts.addr + opts.size, |
| | 431 | }); |
| | 432 | self.phdrs.appendAssumeCapacity(.{ |
| | 433 | .p_type = elf.PT_LOAD, |
| | 434 | .p_offset = off, |
| | 435 | .p_filesz = opts.size, |
| | 436 | .p_vaddr = opts.addr, |
| | 437 | .p_paddr = opts.addr, |
| | 438 | .p_memsz = opts.size, |
| | 439 | .p_align = opts.alignment, |
| | 440 | .p_flags = opts.flags, |
| | 441 | }); |
| | 442 | self.phdr_table_dirty = true; |
| | 443 | return index; |
| | 444 | } |
| | 445 | |
| | 446 | const AllocateAllocSectionOpts = struct { |
| | 447 | name: [:0]const u8, |
| | 448 | phdr_index: u16, |
| | 449 | alignment: u16 = 1, |
| | 450 | flags: u16 = elf.SHF_ALLOC, |
| | 451 | type: u32 = elf.SHT_PROGBITS, |
| | 452 | }; |
| | 453 | |
| | 454 | fn allocateAllocSection(self: *Elf, opts: AllocateAllocSectionOpts) error{OutOfMemory}!u16 { |
| | 455 | const gpa = self.base.allocator; |
| | 456 | const phdr = &self.phdrs.items[opts.phdr_index]; |
| | 457 | const index = @as(u16, @intCast(self.shdrs.items.len)); |
| | 458 | try self.shdrs.ensureUnusedCapacity(gpa, 1); |
| | 459 | const sh_name = try self.shstrtab.insert(gpa, opts.name); |
| | 460 | try self.phdr_to_shdr_table.putNoClobber(gpa, index, opts.phdr_index); |
| | 461 | log.debug("allocating '{s}' in phdr({d}) from 0x{x} to 0x{x} (0x{x} - 0x{x})", .{ |
| | 462 | opts.name, |
| | 463 | opts.phdr_index, |
| | 464 | phdr.p_offset, |
| | 465 | phdr.p_offset + phdr.p_filesz, |
| | 466 | phdr.p_vaddr, |
| | 467 | phdr.p_vaddr + phdr.p_memsz, |
| | 468 | }); |
| | 469 | self.shdrs.appendAssumeCapacity(.{ |
| | 470 | .sh_name = sh_name, |
| | 471 | .sh_type = opts.type, |
| | 472 | .sh_flags = opts.flags, |
| | 473 | .sh_addr = phdr.p_vaddr, |
| | 474 | .sh_offset = phdr.p_offset, |
| | 475 | .sh_size = phdr.p_filesz, |
| | 476 | .sh_link = 0, |
| | 477 | .sh_info = 0, |
| | 478 | .sh_addralign = opts.alignment, |
| | 479 | .sh_entsize = 0, |
| | 480 | }); |
| | 481 | self.shdr_table_dirty = true; |
| | 482 | return index; |
| | 483 | } |
| | 484 | |
| | 485 | const AllocateNonAllocSectionOpts = struct { |
| | 486 | name: [:0]const u8, |
| | 487 | size: u64, |
| | 488 | alignment: u16 = 1, |
| | 489 | flags: u32 = 0, |
| | 490 | type: u32 = elf.SHT_PROGBITS, |
| | 491 | link: u32 = 0, |
| | 492 | info: u32 = 0, |
| | 493 | entsize: u64 = 0, |
| | 494 | }; |
| | 495 | |
| | 496 | fn allocateNonAllocSection(self: *Elf, opts: AllocateNonAllocSectionOpts) error{OutOfMemory}!u16 { |
| | 497 | const index = @as(u16, @intCast(self.shdrs.items.len)); |
| | 498 | try self.shdrs.ensureUnusedCapacity(self.base.allocator, 1); |
| | 499 | const sh_name = try self.shstrtab.insert(self.base.allocator, opts.name); |
| | 500 | const off = self.findFreeSpace(opts.size, opts.alignment); |
| | 501 | log.debug("allocating '{s}' from 0x{x} to 0x{x} ", .{ opts.name, off, off + opts.size }); |
| | 502 | self.shdrs.appendAssumeCapacity(.{ |
| | 503 | .sh_name = sh_name, |
| | 504 | .sh_type = opts.type, |
| | 505 | .sh_flags = opts.flags, |
| | 506 | .sh_addr = 0, |
| | 507 | .sh_offset = off, |
| | 508 | .sh_size = opts.size, |
| | 509 | .sh_link = opts.link, |
| | 510 | .sh_info = opts.info, |
| | 511 | .sh_addralign = opts.alignment, |
| | 512 | .sh_entsize = opts.entsize, |
| | 513 | }); |
| | 514 | self.shdr_table_dirty = true; |
| | 515 | return index; |
| | 516 | } |
| | 517 | |
| 402 | pub fn populateMissingMetadata(self: *Elf) !void { | 518 | pub fn populateMissingMetadata(self: *Elf) !void { |
| 403 | const gpa = self.base.allocator; | 519 | const gpa = self.base.allocator; |
| 404 | const small_ptr = switch (self.ptr_width) { | 520 | const small_ptr = switch (self.ptr_width) { |
| ... | @@ -429,7 +545,6 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -429,7 +545,6 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 429 | | 545 | |
| 430 | if (self.phdr_table_load_index == null) { | 546 | if (self.phdr_table_load_index == null) { |
| 431 | self.phdr_table_load_index = @intCast(self.phdrs.items.len); | 547 | self.phdr_table_load_index = @intCast(self.phdrs.items.len); |
| 432 | // TODO Same as for GOT | | |
| 433 | try self.phdrs.append(gpa, .{ | 548 | try self.phdrs.append(gpa, .{ |
| 434 | .p_type = elf.PT_LOAD, | 549 | .p_type = elf.PT_LOAD, |
| 435 | .p_offset = 0, | 550 | .p_offset = 0, |
| ... | @@ -444,401 +559,200 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -444,401 +559,200 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 444 | } | 559 | } |
| 445 | | 560 | |
| 446 | if (self.phdr_load_re_index == null) { | 561 | if (self.phdr_load_re_index == null) { |
| 447 | self.phdr_load_re_index = @intCast(self.phdrs.items.len); | 562 | self.phdr_load_re_index = try self.allocateSegment(.{ |
| 448 | const file_size = self.base.options.program_code_size_hint; | 563 | .addr = self.defaultEntryAddress(), |
| 449 | const p_align = self.page_size; | 564 | .size = self.base.options.program_code_size_hint, |
| 450 | const off = self.findFreeSpace(file_size, p_align); | 565 | .alignment = self.page_size, |
| 451 | log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size }); | 566 | .flags = elf.PF_X | elf.PF_R | elf.PF_W, |
| 452 | const entry_addr = self.defaultEntryAddress(); | | |
| 453 | try self.phdrs.append(gpa, .{ | | |
| 454 | .p_type = elf.PT_LOAD, | | |
| 455 | .p_offset = off, | | |
| 456 | .p_filesz = file_size, | | |
| 457 | .p_vaddr = entry_addr, | | |
| 458 | .p_paddr = entry_addr, | | |
| 459 | .p_memsz = file_size, | | |
| 460 | .p_align = p_align, | | |
| 461 | .p_flags = elf.PF_X | elf.PF_R | elf.PF_W, | | |
| 462 | }); | 567 | }); |
| 463 | self.entry_addr = null; | 568 | self.entry_addr = null; |
| 464 | self.phdr_table_dirty = true; | | |
| 465 | } | 569 | } |
| 466 | | 570 | |
| 467 | if (self.phdr_got_index == null) { | 571 | if (self.phdr_got_index == null) { |
| 468 | self.phdr_got_index = @intCast(self.phdrs.items.len); | | |
| 469 | const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint; | | |
| 470 | // We really only need ptr alignment but since we are using PROGBITS, linux requires | | |
| 471 | // page align. | | |
| 472 | const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); | | |
| 473 | const off = self.findFreeSpace(file_size, p_align); | | |
| 474 | log.debug("found PT_LOAD GOT free space 0x{x} to 0x{x}", .{ off, off + file_size }); | | |
| 475 | // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at. | 572 | // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at. |
| 476 | // we'll need to re-use that function anyway, in case the GOT grows and overlaps something | 573 | // we'll need to re-use that function anyway, in case the GOT grows and overlaps something |
| 477 | // else in virtual memory. | 574 | // else in virtual memory. |
| 478 | const got_addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0x4000000 else 0x8000; | 575 | const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x4000000 else 0x8000; |
| 479 | try self.phdrs.append(gpa, .{ | 576 | // We really only need ptr alignment but since we are using PROGBITS, linux requires |
| 480 | .p_type = elf.PT_LOAD, | 577 | // page align. |
| 481 | .p_offset = off, | 578 | const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); |
| 482 | .p_filesz = file_size, | 579 | self.phdr_got_index = try self.allocateSegment(.{ |
| 483 | .p_vaddr = got_addr, | 580 | .addr = addr, |
| 484 | .p_paddr = got_addr, | 581 | .size = @as(u64, ptr_size) * self.base.options.symbol_count_hint, |
| 485 | .p_memsz = file_size, | 582 | .alignment = alignment, |
| 486 | .p_align = p_align, | 583 | .flags = elf.PF_R | elf.PF_W, |
| 487 | .p_flags = elf.PF_R | elf.PF_W, | | |
| 488 | }); | 584 | }); |
| 489 | self.phdr_table_dirty = true; | | |
| 490 | } | 585 | } |
| 491 | | 586 | |
| 492 | if (self.phdr_load_ro_index == null) { | 587 | if (self.phdr_load_ro_index == null) { |
| 493 | self.phdr_load_ro_index = @intCast(self.phdrs.items.len); | | |
| 494 | // TODO Find a hint about how much data need to be in rodata ? | | |
| 495 | const file_size = 1024; | | |
| 496 | // Same reason as for GOT | | |
| 497 | const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); | | |
| 498 | const off = self.findFreeSpace(file_size, p_align); | | |
| 499 | log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}", .{ off, off + file_size }); | | |
| 500 | // TODO Same as for GOT | 588 | // TODO Same as for GOT |
| 501 | const rodata_addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0xc000000 else 0xa000; | 589 | const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0xc000000 else 0xa000; |
| 502 | try self.phdrs.append(gpa, .{ | 590 | // Same reason as for GOT |
| 503 | .p_type = elf.PT_LOAD, | 591 | const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); |
| 504 | .p_offset = off, | 592 | self.phdr_load_ro_index = try self.allocateSegment(.{ |
| 505 | .p_filesz = file_size, | 593 | .addr = addr, |
| 506 | .p_vaddr = rodata_addr, | 594 | .size = 1024, |
| 507 | .p_paddr = rodata_addr, | 595 | .alignment = alignment, |
| 508 | .p_memsz = file_size, | 596 | .flags = elf.PF_R | elf.PF_W, |
| 509 | .p_align = p_align, | | |
| 510 | .p_flags = elf.PF_R | elf.PF_W, | | |
| 511 | }); | 597 | }); |
| 512 | self.phdr_table_dirty = true; | | |
| 513 | } | 598 | } |
| 514 | | 599 | |
| 515 | if (self.phdr_load_rw_index == null) { | 600 | if (self.phdr_load_rw_index == null) { |
| 516 | self.phdr_load_rw_index = @intCast(self.phdrs.items.len); | | |
| 517 | // TODO Find a hint about how much data need to be in data ? | | |
| 518 | const file_size = 1024; | | |
| 519 | // Same reason as for GOT | | |
| 520 | const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); | | |
| 521 | const off = self.findFreeSpace(file_size, p_align); | | |
| 522 | log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}", .{ off, off + file_size }); | | |
| 523 | // TODO Same as for GOT | 601 | // TODO Same as for GOT |
| 524 | const rwdata_addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0x10000000 else 0xc000; | 602 | const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x10000000 else 0xc000; |
| 525 | try self.phdrs.append(gpa, .{ | 603 | // Same reason as for GOT |
| 526 | .p_type = elf.PT_LOAD, | 604 | const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); |
| 527 | .p_offset = off, | 605 | self.phdr_load_rw_index = try self.allocateSegment(.{ |
| 528 | .p_filesz = file_size, | 606 | .addr = addr, |
| 529 | .p_vaddr = rwdata_addr, | 607 | .size = 1024, |
| 530 | .p_paddr = rwdata_addr, | 608 | .alignment = alignment, |
| 531 | .p_memsz = file_size, | 609 | .flags = elf.PF_R | elf.PF_W, |
| 532 | .p_align = p_align, | | |
| 533 | .p_flags = elf.PF_R | elf.PF_W, | | |
| 534 | }); | 610 | }); |
| 535 | self.phdr_table_dirty = true; | | |
| 536 | } | 611 | } |
| 537 | | 612 | |
| 538 | if (self.phdr_load_zerofill_index == null) { | 613 | if (self.phdr_load_zerofill_index == null) { |
| 539 | self.phdr_load_zerofill_index = @intCast(self.phdrs.items.len); | | |
| 540 | const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); | | |
| 541 | const off = self.phdrs.items[self.phdr_load_rw_index.?].p_offset; | | |
| 542 | log.debug("found PT_LOAD zerofill free space 0x{x} to 0x{x}", .{ off, off }); | | |
| 543 | // TODO Same as for GOT | 614 | // TODO Same as for GOT |
| 544 | const addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0x14000000 else 0xf000; | 615 | const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x14000000 else 0xf000; |
| 545 | try self.phdrs.append(gpa, .{ | 616 | const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); |
| 546 | .p_type = elf.PT_LOAD, | 617 | self.phdr_load_zerofill_index = try self.allocateSegment(.{ |
| 547 | .p_offset = off, | 618 | .addr = addr, |
| 548 | .p_filesz = 0, | 619 | .size = 0, |
| 549 | .p_vaddr = addr, | 620 | .alignment = alignment, |
| 550 | .p_paddr = addr, | 621 | .flags = elf.PF_R | elf.PF_W, |
| 551 | .p_memsz = 0, | | |
| 552 | .p_align = p_align, | | |
| 553 | .p_flags = elf.PF_R | elf.PF_W, | | |
| 554 | }); | 622 | }); |
| 555 | self.phdr_table_dirty = true; | 623 | const phdr = &self.phdrs.items[self.phdr_load_zerofill_index.?]; |
| | 624 | phdr.p_offset = self.phdrs.items[self.phdr_load_rw_index.?].p_offset; // .bss overlaps .data |
| 556 | } | 625 | } |
| 557 | | 626 | |
| 558 | if (self.shstrtab_section_index == null) { | 627 | if (self.shstrtab_section_index == null) { |
| 559 | self.shstrtab_section_index = @intCast(self.shdrs.items.len); | | |
| 560 | assert(self.shstrtab.buffer.items.len == 0); | 628 | assert(self.shstrtab.buffer.items.len == 0); |
| 561 | try self.shstrtab.buffer.append(gpa, 0); // need a 0 at position 0 | 629 | try self.shstrtab.buffer.append(gpa, 0); // need a 0 at position 0 |
| 562 | const off = self.findFreeSpace(self.shstrtab.buffer.items.len, 1); | 630 | self.shstrtab_section_index = try self.allocateNonAllocSection(.{ |
| 563 | log.debug("found .shstrtab free space 0x{x} to 0x{x}", .{ off, off + self.shstrtab.buffer.items.len }); | 631 | .name = ".shstrtab", |
| 564 | try self.shdrs.append(gpa, .{ | 632 | .size = @intCast(self.shstrtab.buffer.items.len), |
| 565 | .sh_name = try self.shstrtab.insert(gpa, ".shstrtab"), | 633 | .type = elf.SHT_STRTAB, |
| 566 | .sh_type = elf.SHT_STRTAB, | | |
| 567 | .sh_flags = 0, | | |
| 568 | .sh_addr = 0, | | |
| 569 | .sh_offset = off, | | |
| 570 | .sh_size = self.shstrtab.buffer.items.len, | | |
| 571 | .sh_link = 0, | | |
| 572 | .sh_info = 0, | | |
| 573 | .sh_addralign = 1, | | |
| 574 | .sh_entsize = 0, | | |
| 575 | }); | 634 | }); |
| 576 | self.shstrtab_dirty = true; | 635 | self.shstrtab_dirty = true; |
| 577 | self.shdr_table_dirty = true; | | |
| 578 | } | 636 | } |
| 579 | | 637 | |
| 580 | if (self.strtab_section_index == null) { | 638 | if (self.strtab_section_index == null) { |
| 581 | self.strtab_section_index = @intCast(self.shdrs.items.len); | | |
| 582 | assert(self.strtab.buffer.items.len == 0); | 639 | assert(self.strtab.buffer.items.len == 0); |
| 583 | try self.strtab.buffer.append(gpa, 0); // need a 0 at position 0 | 640 | try self.strtab.buffer.append(gpa, 0); // need a 0 at position 0 |
| 584 | const off = self.findFreeSpace(self.strtab.buffer.items.len, 1); | 641 | self.strtab_section_index = try self.allocateNonAllocSection(.{ |
| 585 | log.debug("found .strtab free space 0x{x} to 0x{x}", .{ off, off + self.strtab.buffer.items.len }); | 642 | .name = ".strtab", |
| 586 | try self.shdrs.append(gpa, .{ | 643 | .size = @intCast(self.strtab.buffer.items.len), |
| 587 | .sh_name = try self.shstrtab.insert(gpa, ".strtab"), | 644 | .type = elf.SHT_STRTAB, |
| 588 | .sh_type = elf.SHT_STRTAB, | | |
| 589 | .sh_flags = 0, | | |
| 590 | .sh_addr = 0, | | |
| 591 | .sh_offset = off, | | |
| 592 | .sh_size = self.strtab.buffer.items.len, | | |
| 593 | .sh_link = 0, | | |
| 594 | .sh_info = 0, | | |
| 595 | .sh_addralign = 1, | | |
| 596 | .sh_entsize = 0, | | |
| 597 | }); | 645 | }); |
| 598 | self.strtab_dirty = true; | 646 | self.strtab_dirty = true; |
| 599 | self.shdr_table_dirty = true; | | |
| 600 | } | 647 | } |
| 601 | | 648 | |
| 602 | if (self.text_section_index == null) { | 649 | if (self.text_section_index == null) { |
| 603 | self.text_section_index = @intCast(self.shdrs.items.len); | 650 | self.text_section_index = try self.allocateAllocSection(.{ |
| 604 | const phdr = &self.phdrs.items[self.phdr_load_re_index.?]; | 651 | .name = ".text", |
| 605 | try self.shdrs.append(gpa, .{ | 652 | .phdr_index = self.phdr_load_re_index.?, |
| 606 | .sh_name = try self.shstrtab.insert(gpa, ".text"), | 653 | .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR, |
| 607 | .sh_type = elf.SHT_PROGBITS, | | |
| 608 | .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR, | | |
| 609 | .sh_addr = phdr.p_vaddr, | | |
| 610 | .sh_offset = phdr.p_offset, | | |
| 611 | .sh_size = phdr.p_filesz, | | |
| 612 | .sh_link = 0, | | |
| 613 | .sh_info = 0, | | |
| 614 | .sh_addralign = 1, | | |
| 615 | .sh_entsize = 0, | | |
| 616 | }); | 654 | }); |
| 617 | try self.phdr_to_shdr_table.putNoClobber(gpa, self.text_section_index.?, self.phdr_load_re_index.?); | | |
| 618 | try self.last_atom_and_free_list_table.putNoClobber(gpa, self.text_section_index.?, .{}); | 655 | try self.last_atom_and_free_list_table.putNoClobber(gpa, self.text_section_index.?, .{}); |
| 619 | self.shdr_table_dirty = true; | | |
| 620 | } | 656 | } |
| 621 | | 657 | |
| 622 | if (self.got_section_index == null) { | 658 | if (self.got_section_index == null) { |
| 623 | self.got_section_index = @intCast(self.shdrs.items.len); | 659 | self.got_section_index = try self.allocateAllocSection(.{ |
| 624 | const phdr = &self.phdrs.items[self.phdr_got_index.?]; | 660 | .name = ".got", |
| 625 | try self.shdrs.append(gpa, .{ | 661 | .phdr_index = self.phdr_got_index.?, |
| 626 | .sh_name = try self.shstrtab.insert(gpa, ".got"), | 662 | .alignment = ptr_size, |
| 627 | .sh_type = elf.SHT_PROGBITS, | | |
| 628 | .sh_flags = elf.SHF_ALLOC, | | |
| 629 | .sh_addr = phdr.p_vaddr, | | |
| 630 | .sh_offset = phdr.p_offset, | | |
| 631 | .sh_size = phdr.p_filesz, | | |
| 632 | .sh_link = 0, | | |
| 633 | .sh_info = 0, | | |
| 634 | .sh_addralign = @as(u16, ptr_size), | | |
| 635 | .sh_entsize = 0, | | |
| 636 | }); | 663 | }); |
| 637 | try self.phdr_to_shdr_table.putNoClobber(gpa, self.got_section_index.?, self.phdr_got_index.?); | | |
| 638 | self.shdr_table_dirty = true; | | |
| 639 | } | 664 | } |
| 640 | | 665 | |
| 641 | if (self.rodata_section_index == null) { | 666 | if (self.rodata_section_index == null) { |
| 642 | self.rodata_section_index = @intCast(self.shdrs.items.len); | 667 | self.rodata_section_index = try self.allocateAllocSection(.{ |
| 643 | const phdr = &self.phdrs.items[self.phdr_load_ro_index.?]; | 668 | .name = ".rodata", |
| 644 | try self.shdrs.append(gpa, .{ | 669 | .phdr_index = self.phdr_load_ro_index.?, |
| 645 | .sh_name = try self.shstrtab.insert(gpa, ".rodata"), | | |
| 646 | .sh_type = elf.SHT_PROGBITS, | | |
| 647 | .sh_flags = elf.SHF_ALLOC, | | |
| 648 | .sh_addr = phdr.p_vaddr, | | |
| 649 | .sh_offset = phdr.p_offset, | | |
| 650 | .sh_size = phdr.p_filesz, | | |
| 651 | .sh_link = 0, | | |
| 652 | .sh_info = 0, | | |
| 653 | .sh_addralign = 1, | | |
| 654 | .sh_entsize = 0, | | |
| 655 | }); | 670 | }); |
| 656 | try self.phdr_to_shdr_table.putNoClobber(gpa, self.rodata_section_index.?, self.phdr_load_ro_index.?); | | |
| 657 | try self.last_atom_and_free_list_table.putNoClobber(gpa, self.rodata_section_index.?, .{}); | 671 | try self.last_atom_and_free_list_table.putNoClobber(gpa, self.rodata_section_index.?, .{}); |
| 658 | self.shdr_table_dirty = true; | | |
| 659 | } | 672 | } |
| 660 | | 673 | |
| 661 | if (self.data_section_index == null) { | 674 | if (self.data_section_index == null) { |
| 662 | self.data_section_index = @intCast(self.shdrs.items.len); | 675 | self.data_section_index = try self.allocateAllocSection(.{ |
| 663 | const phdr = &self.phdrs.items[self.phdr_load_rw_index.?]; | 676 | .name = ".data", |
| 664 | try self.shdrs.append(gpa, .{ | 677 | .phdr_index = self.phdr_load_rw_index.?, |
| 665 | .sh_name = try self.shstrtab.insert(gpa, ".data"), | 678 | .alignment = ptr_size, |
| 666 | .sh_type = elf.SHT_PROGBITS, | 679 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, |
| 667 | .sh_flags = elf.SHF_WRITE | elf.SHF_ALLOC, | | |
| 668 | .sh_addr = phdr.p_vaddr, | | |
| 669 | .sh_offset = phdr.p_offset, | | |
| 670 | .sh_size = phdr.p_filesz, | | |
| 671 | .sh_link = 0, | | |
| 672 | .sh_info = 0, | | |
| 673 | .sh_addralign = @as(u16, ptr_size), | | |
| 674 | .sh_entsize = 0, | | |
| 675 | }); | 680 | }); |
| 676 | try self.phdr_to_shdr_table.putNoClobber(gpa, self.data_section_index.?, self.phdr_load_rw_index.?); | | |
| 677 | try self.last_atom_and_free_list_table.putNoClobber(gpa, self.data_section_index.?, .{}); | 681 | try self.last_atom_and_free_list_table.putNoClobber(gpa, self.data_section_index.?, .{}); |
| 678 | self.shdr_table_dirty = true; | | |
| 679 | } | 682 | } |
| 680 | | 683 | |
| 681 | if (self.bss_section_index == null) { | 684 | if (self.bss_section_index == null) { |
| 682 | self.bss_section_index = @intCast(self.shdrs.items.len); | 685 | self.bss_section_index = try self.allocateAllocSection(.{ |
| 683 | const phdr = &self.phdrs.items[self.phdr_load_zerofill_index.?]; | 686 | .name = ".bss", |
| 684 | try self.shdrs.append(gpa, .{ | 687 | .phdr_index = self.phdr_load_zerofill_index.?, |
| 685 | .sh_name = try self.shstrtab.insert(gpa, ".bss"), | 688 | .alignment = ptr_size, |
| 686 | .sh_type = elf.SHT_NOBITS, | 689 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, |
| 687 | .sh_flags = elf.SHF_WRITE | elf.SHF_ALLOC, | 690 | .type = elf.SHT_NOBITS, |
| 688 | .sh_addr = phdr.p_vaddr, | | |
| 689 | .sh_offset = phdr.p_offset, | | |
| 690 | .sh_size = phdr.p_filesz, | | |
| 691 | .sh_link = 0, | | |
| 692 | .sh_info = 0, | | |
| 693 | .sh_addralign = @as(u16, ptr_size), | | |
| 694 | .sh_entsize = 0, | | |
| 695 | }); | 691 | }); |
| 696 | try self.phdr_to_shdr_table.putNoClobber(gpa, self.bss_section_index.?, self.phdr_load_zerofill_index.?); | | |
| 697 | try self.last_atom_and_free_list_table.putNoClobber(gpa, self.bss_section_index.?, .{}); | 692 | try self.last_atom_and_free_list_table.putNoClobber(gpa, self.bss_section_index.?, .{}); |
| 698 | self.shdr_table_dirty = true; | | |
| 699 | } | 693 | } |
| 700 | | 694 | |
| 701 | if (self.symtab_section_index == null) { | 695 | if (self.symtab_section_index == null) { |
| 702 | self.symtab_section_index = @intCast(self.shdrs.items.len); | | |
| 703 | const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym); | 696 | const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym); |
| 704 | const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym); | 697 | const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym); |
| 705 | const file_size = self.base.options.symbol_count_hint * each_size; | 698 | self.symtab_section_index = try self.allocateNonAllocSection(.{ |
| 706 | const off = self.findFreeSpace(file_size, min_align); | 699 | .name = ".symtab", |
| 707 | log.debug("found symtab free space 0x{x} to 0x{x}", .{ off, off + file_size }); | 700 | .size = self.base.options.symbol_count_hint * each_size, |
| 708 | try self.shdrs.append(gpa, .{ | 701 | .alignment = min_align, |
| 709 | .sh_name = try self.shstrtab.insert(gpa, ".symtab"), | 702 | .type = elf.SHT_SYMTAB, |
| 710 | .sh_type = elf.SHT_SYMTAB, | 703 | .link = self.strtab_section_index.?, // Index of associated string table |
| 711 | .sh_flags = 0, | 704 | .info = @intCast(self.symbols.items.len), |
| 712 | .sh_addr = 0, | 705 | .entsize = each_size, |
| 713 | .sh_offset = off, | | |
| 714 | .sh_size = file_size, | | |
| 715 | // The section header index of the associated string table. | | |
| 716 | .sh_link = self.strtab_section_index.?, | | |
| 717 | .sh_info = @intCast(self.symbols.items.len), | | |
| 718 | .sh_addralign = min_align, | | |
| 719 | .sh_entsize = each_size, | | |
| 720 | }); | 706 | }); |
| 721 | self.shdr_table_dirty = true; | 707 | self.shdr_table_dirty = true; |
| 722 | } | 708 | } |
| 723 | | 709 | |
| 724 | if (self.dwarf) |*dw| { | 710 | if (self.dwarf) |*dw| { |
| 725 | if (self.debug_str_section_index == null) { | 711 | if (self.debug_str_section_index == null) { |
| 726 | self.debug_str_section_index = @intCast(self.shdrs.items.len); | | |
| 727 | assert(dw.strtab.buffer.items.len == 0); | 712 | assert(dw.strtab.buffer.items.len == 0); |
| 728 | try dw.strtab.buffer.append(gpa, 0); | 713 | try dw.strtab.buffer.append(gpa, 0); |
| 729 | try self.shdrs.append(gpa, .{ | 714 | self.debug_str_section_index = try self.allocateNonAllocSection(.{ |
| 730 | .sh_name = try self.shstrtab.insert(gpa, ".debug_str"), | 715 | .name = ".debug_str", |
| 731 | .sh_type = elf.SHT_PROGBITS, | 716 | .size = @intCast(dw.strtab.buffer.items.len), |
| 732 | .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS, | 717 | .flags = elf.SHF_MERGE | elf.SHF_STRINGS, |
| 733 | .sh_addr = 0, | 718 | .entsize = 1, |
| 734 | .sh_offset = 0, | | |
| 735 | .sh_size = 0, | | |
| 736 | .sh_link = 0, | | |
| 737 | .sh_info = 0, | | |
| 738 | .sh_addralign = 1, | | |
| 739 | .sh_entsize = 1, | | |
| 740 | }); | 719 | }); |
| 741 | self.debug_strtab_dirty = true; | 720 | self.debug_strtab_dirty = true; |
| 742 | self.shdr_table_dirty = true; | | |
| 743 | } | 721 | } |
| 744 | | 722 | |
| 745 | if (self.debug_info_section_index == null) { | 723 | if (self.debug_info_section_index == null) { |
| 746 | self.debug_info_section_index = @intCast(self.shdrs.items.len); | 724 | self.debug_info_section_index = try self.allocateNonAllocSection(.{ |
| 747 | const file_size_hint = 200; | 725 | .name = ".debug_info", |
| 748 | const p_align = 1; | 726 | .size = 200, |
| 749 | const off = self.findFreeSpace(file_size_hint, p_align); | 727 | .alignment = 1, |
| 750 | log.debug("found .debug_info free space 0x{x} to 0x{x}", .{ | | |
| 751 | off, | | |
| 752 | off + file_size_hint, | | |
| 753 | }); | | |
| 754 | try self.shdrs.append(gpa, .{ | | |
| 755 | .sh_name = try self.shstrtab.insert(gpa, ".debug_info"), | | |
| 756 | .sh_type = elf.SHT_PROGBITS, | | |
| 757 | .sh_flags = 0, | | |
| 758 | .sh_addr = 0, | | |
| 759 | .sh_offset = off, | | |
| 760 | .sh_size = file_size_hint, | | |
| 761 | .sh_link = 0, | | |
| 762 | .sh_info = 0, | | |
| 763 | .sh_addralign = p_align, | | |
| 764 | .sh_entsize = 0, | | |
| 765 | }); | 728 | }); |
| 766 | self.shdr_table_dirty = true; | | |
| 767 | self.debug_info_header_dirty = true; | 729 | self.debug_info_header_dirty = true; |
| 768 | } | 730 | } |
| 769 | | 731 | |
| 770 | if (self.debug_abbrev_section_index == null) { | 732 | if (self.debug_abbrev_section_index == null) { |
| 771 | self.debug_abbrev_section_index = @intCast(self.shdrs.items.len); | 733 | self.debug_abbrev_section_index = try self.allocateNonAllocSection(.{ |
| 772 | const file_size_hint = 128; | 734 | .name = ".debug_abbrev", |
| 773 | const p_align = 1; | 735 | .size = 128, |
| 774 | const off = self.findFreeSpace(file_size_hint, p_align); | 736 | .alignment = 1, |
| 775 | log.debug("found .debug_abbrev free space 0x{x} to 0x{x}", .{ | | |
| 776 | off, | | |
| 777 | off + file_size_hint, | | |
| 778 | }); | 737 | }); |
| 779 | try self.shdrs.append(gpa, .{ | | |
| 780 | .sh_name = try self.shstrtab.insert(gpa, ".debug_abbrev"), | | |
| 781 | .sh_type = elf.SHT_PROGBITS, | | |
| 782 | .sh_flags = 0, | | |
| 783 | .sh_addr = 0, | | |
| 784 | .sh_offset = off, | | |
| 785 | .sh_size = file_size_hint, | | |
| 786 | .sh_link = 0, | | |
| 787 | .sh_info = 0, | | |
| 788 | .sh_addralign = p_align, | | |
| 789 | .sh_entsize = 0, | | |
| 790 | }); | | |
| 791 | self.shdr_table_dirty = true; | | |
| 792 | self.debug_abbrev_section_dirty = true; | 738 | self.debug_abbrev_section_dirty = true; |
| 793 | } | 739 | } |
| 794 | | 740 | |
| 795 | if (self.debug_aranges_section_index == null) { | 741 | if (self.debug_aranges_section_index == null) { |
| 796 | self.debug_aranges_section_index = @intCast(self.shdrs.items.len); | 742 | self.debug_aranges_section_index = try self.allocateNonAllocSection(.{ |
| 797 | const file_size_hint = 160; | 743 | .name = ".debug_aranges", |
| 798 | const p_align = 16; | 744 | .size = 160, |
| 799 | const off = self.findFreeSpace(file_size_hint, p_align); | 745 | .alignment = 16, |
| 800 | log.debug("found .debug_aranges free space 0x{x} to 0x{x}", .{ | | |
| 801 | off, | | |
| 802 | off + file_size_hint, | | |
| 803 | }); | | |
| 804 | try self.shdrs.append(gpa, .{ | | |
| 805 | .sh_name = try self.shstrtab.insert(gpa, ".debug_aranges"), | | |
| 806 | .sh_type = elf.SHT_PROGBITS, | | |
| 807 | .sh_flags = 0, | | |
| 808 | .sh_addr = 0, | | |
| 809 | .sh_offset = off, | | |
| 810 | .sh_size = file_size_hint, | | |
| 811 | .sh_link = 0, | | |
| 812 | .sh_info = 0, | | |
| 813 | .sh_addralign = p_align, | | |
| 814 | .sh_entsize = 0, | | |
| 815 | }); | 746 | }); |
| 816 | self.shdr_table_dirty = true; | | |
| 817 | self.debug_aranges_section_dirty = true; | 747 | self.debug_aranges_section_dirty = true; |
| 818 | } | 748 | } |
| 819 | | 749 | |
| 820 | if (self.debug_line_section_index == null) { | 750 | if (self.debug_line_section_index == null) { |
| 821 | self.debug_line_section_index = @intCast(self.shdrs.items.len); | 751 | self.debug_line_section_index = try self.allocateNonAllocSection(.{ |
| 822 | const file_size_hint = 250; | 752 | .name = ".debug_line", |
| 823 | const p_align = 1; | 753 | .size = 250, |
| 824 | const off = self.findFreeSpace(file_size_hint, p_align); | 754 | .alignment = 1, |
| 825 | log.debug("found .debug_line free space 0x{x} to 0x{x}", .{ | | |
| 826 | off, | | |
| 827 | off + file_size_hint, | | |
| 828 | }); | 755 | }); |
| 829 | try self.shdrs.append(gpa, .{ | | |
| 830 | .sh_name = try self.shstrtab.insert(gpa, ".debug_line"), | | |
| 831 | .sh_type = elf.SHT_PROGBITS, | | |
| 832 | .sh_flags = 0, | | |
| 833 | .sh_addr = 0, | | |
| 834 | .sh_offset = off, | | |
| 835 | .sh_size = file_size_hint, | | |
| 836 | .sh_link = 0, | | |
| 837 | .sh_info = 0, | | |
| 838 | .sh_addralign = p_align, | | |
| 839 | .sh_entsize = 0, | | |
| 840 | }); | | |
| 841 | self.shdr_table_dirty = true; | | |
| 842 | self.debug_line_header_dirty = true; | 756 | self.debug_line_header_dirty = true; |
| 843 | } | 757 | } |
| 844 | } | 758 | } |
| ... | @@ -907,7 +821,6 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -907,7 +821,6 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 907 | } | 821 | } |
| 908 | | 822 | |
| 909 | pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { | 823 | pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { |
| 910 | // TODO Also detect virtual address collisions. | | |
| 911 | const shdr = &self.shdrs.items[shdr_index]; | 824 | const shdr = &self.shdrs.items[shdr_index]; |
| 912 | const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?; | 825 | const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?; |
| 913 | const phdr = &self.phdrs.items[phdr_index]; | 826 | const phdr = &self.phdrs.items[phdr_index]; |
| ... | @@ -922,8 +835,8 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { | ... | @@ -922,8 +835,8 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { |
| 922 | } else shdr.sh_size; | 835 | } else shdr.sh_size; |
| 923 | shdr.sh_size = 0; | 836 | shdr.sh_size = 0; |
| 924 | | 837 | |
| 925 | log.debug("new '{?s}' file offset 0x{x} to 0x{x}", .{ | 838 | log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{ |
| 926 | self.shstrtab.get(shdr.sh_name), | 839 | self.shstrtab.getAssumeExists(shdr.sh_name), |
| 927 | new_offset, | 840 | new_offset, |
| 928 | new_offset + existing_size, | 841 | new_offset + existing_size, |
| 929 | }); | 842 | }); |
| ... | @@ -935,6 +848,9 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { | ... | @@ -935,6 +848,9 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { |
| 935 | phdr.p_offset = new_offset; | 848 | phdr.p_offset = new_offset; |
| 936 | } | 849 | } |
| 937 | | 850 | |
| | 851 | const mem_capacity = self.allocatedVirtualSize(phdr.p_vaddr); |
| | 852 | assert(needed_size <= mem_capacity); // TODO grow section in virtual memory |
| | 853 | |
| 938 | shdr.sh_size = needed_size; | 854 | shdr.sh_size = needed_size; |
| 939 | phdr.p_memsz = needed_size; | 855 | phdr.p_memsz = needed_size; |
| 940 | | 856 | |
| ... | @@ -1160,7 +1076,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node | ... | @@ -1160,7 +1076,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1160 | for (self.file(index).?.zig_module.atoms.keys()) |atom_index| { | 1076 | for (self.file(index).?.zig_module.atoms.keys()) |atom_index| { |
| 1161 | const atom_ptr = self.atom(atom_index).?; | 1077 | const atom_ptr = self.atom(atom_index).?; |
| 1162 | if (!atom_ptr.alive) continue; | 1078 | if (!atom_ptr.alive) continue; |
| 1163 | const shdr = &self.shdrs.items[atom_ptr.output_section_index]; | 1079 | const shdr = &self.shdrs.items[atom_ptr.outputShndx().?]; |
| 1164 | const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr; | 1080 | const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr; |
| 1165 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; | 1081 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; |
| 1166 | const code = try gpa.alloc(u8, size); | 1082 | const code = try gpa.alloc(u8, size); |
| ... | @@ -1190,6 +1106,16 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node | ... | @@ -1190,6 +1106,16 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1190 | try self.updateSymtabSize(); | 1106 | try self.updateSymtabSize(); |
| 1191 | try self.writeSymtab(); | 1107 | try self.writeSymtab(); |
| 1192 | | 1108 | |
| | 1109 | // .bss always overlaps .data in file offset, but is zero-sized in file so it doesn't |
| | 1110 | // get mapped by the loader |
| | 1111 | if (self.data_section_index) |data_shndx| blk: { |
| | 1112 | const bss_shndx = self.bss_section_index orelse break :blk; |
| | 1113 | const data_phndx = self.phdr_to_shdr_table.get(data_shndx).?; |
| | 1114 | const bss_phndx = self.phdr_to_shdr_table.get(bss_shndx).?; |
| | 1115 | self.shdrs.items[bss_shndx].sh_offset = self.shdrs.items[data_shndx].sh_offset; |
| | 1116 | self.phdrs.items[bss_phndx].p_offset = self.phdrs.items[data_phndx].p_offset; |
| | 1117 | } |
| | 1118 | |
| 1193 | // Dump the state for easy debugging. | 1119 | // Dump the state for easy debugging. |
| 1194 | // State can be dumped via `--debug-log link_state`. | 1120 | // State can be dumped via `--debug-log link_state`. |
| 1195 | if (build_options.enable_logging) { | 1121 | if (build_options.enable_logging) { |
| ... | @@ -1567,6 +1493,7 @@ fn resolveSymbols(self: *Elf) error{Overflow}!void { | ... | @@ -1567,6 +1493,7 @@ fn resolveSymbols(self: *Elf) error{Overflow}!void { |
| 1567 | /// This routine will prune unneeded objects extracted from archives and | 1493 | /// This routine will prune unneeded objects extracted from archives and |
| 1568 | /// unneeded shared objects. | 1494 | /// unneeded shared objects. |
| 1569 | fn markLive(self: *Elf) void { | 1495 | fn markLive(self: *Elf) void { |
| | 1496 | if (self.zig_module_index) |index| self.file(index).?.markLive(self); |
| 1570 | for (self.objects.items) |index| { | 1497 | for (self.objects.items) |index| { |
| 1571 | const file_ptr = self.file(index).?; | 1498 | const file_ptr = self.file(index).?; |
| 1572 | if (file_ptr.isAlive()) file_ptr.markLive(self); | 1499 | if (file_ptr.isAlive()) file_ptr.markLive(self); |
| ... | @@ -1689,7 +1616,7 @@ fn writeObjects(self: *Elf) !void { | ... | @@ -1689,7 +1616,7 @@ fn writeObjects(self: *Elf) !void { |
| 1689 | const atom_ptr = self.atom(atom_index) orelse continue; | 1616 | const atom_ptr = self.atom(atom_index) orelse continue; |
| 1690 | if (!atom_ptr.alive) continue; | 1617 | if (!atom_ptr.alive) continue; |
| 1691 | | 1618 | |
| 1692 | const shdr = &self.shdrs.items[atom_ptr.output_section_index]; | 1619 | const shdr = &self.shdrs.items[atom_ptr.outputShndx().?]; |
| 1693 | if (shdr.sh_type == elf.SHT_NOBITS) continue; | 1620 | if (shdr.sh_type == elf.SHT_NOBITS) continue; |
| 1694 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; // TODO we don't yet know how to handle non-alloc sections | 1621 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; // TODO we don't yet know how to handle non-alloc sections |
| 1695 | | 1622 | |
| ... | @@ -2563,15 +2490,15 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void { | ... | @@ -2563,15 +2490,15 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void { |
| 2563 | } | 2490 | } |
| 2564 | } | 2491 | } |
| 2565 | | 2492 | |
| 2566 | pub fn getOrCreateMetadataForLazySymbol(self: *Elf, sym: link.File.LazySymbol) !Symbol.Index { | 2493 | pub fn getOrCreateMetadataForLazySymbol(self: *Elf, lazy_sym: link.File.LazySymbol) !Symbol.Index { |
| 2567 | const mod = self.base.options.module.?; | 2494 | const mod = self.base.options.module.?; |
| 2568 | const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl(mod)); | 2495 | const gop = try self.lazy_syms.getOrPut(self.base.allocator, lazy_sym.getDecl(mod)); |
| 2569 | errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); | 2496 | errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); |
| 2570 | if (!gop.found_existing) gop.value_ptr.* = .{}; | 2497 | if (!gop.found_existing) gop.value_ptr.* = .{}; |
| 2571 | const metadata: struct { | 2498 | const metadata: struct { |
| 2572 | symbol_index: *Symbol.Index, | 2499 | symbol_index: *Symbol.Index, |
| 2573 | state: *LazySymbolMetadata.State, | 2500 | state: *LazySymbolMetadata.State, |
| 2574 | } = switch (sym.kind) { | 2501 | } = switch (lazy_sym.kind) { |
| 2575 | .code => .{ | 2502 | .code => .{ |
| 2576 | .symbol_index = &gop.value_ptr.text_symbol_index, | 2503 | .symbol_index = &gop.value_ptr.text_symbol_index, |
| 2577 | .state = &gop.value_ptr.text_state, | 2504 | .state = &gop.value_ptr.text_state, |
| ... | @@ -2583,17 +2510,14 @@ pub fn getOrCreateMetadataForLazySymbol(self: *Elf, sym: link.File.LazySymbol) ! | ... | @@ -2583,17 +2510,14 @@ pub fn getOrCreateMetadataForLazySymbol(self: *Elf, sym: link.File.LazySymbol) ! |
| 2583 | }; | 2510 | }; |
| 2584 | const zig_module = self.file(self.zig_module_index.?).?.zig_module; | 2511 | const zig_module = self.file(self.zig_module_index.?).?.zig_module; |
| 2585 | switch (metadata.state.*) { | 2512 | switch (metadata.state.*) { |
| 2586 | .unused => metadata.symbol_index.* = try zig_module.addAtom(switch (sym.kind) { | 2513 | .unused => metadata.symbol_index.* = try zig_module.addAtom(self), |
| 2587 | .code => self.text_section_index.?, | | |
| 2588 | .const_data => self.rodata_section_index.?, | | |
| 2589 | }, self), | | |
| 2590 | .pending_flush => return metadata.symbol_index.*, | 2514 | .pending_flush => return metadata.symbol_index.*, |
| 2591 | .flushed => {}, | 2515 | .flushed => {}, |
| 2592 | } | 2516 | } |
| 2593 | metadata.state.* = .pending_flush; | 2517 | metadata.state.* = .pending_flush; |
| 2594 | const symbol_index = metadata.symbol_index.*; | 2518 | const symbol_index = metadata.symbol_index.*; |
| 2595 | // anyerror needs to be deferred until flushModule | 2519 | // anyerror needs to be deferred until flushModule |
| 2596 | if (sym.getDecl(mod) != .none) try self.updateLazySymbol(sym, symbol_index); | 2520 | if (lazy_sym.getDecl(mod) != .none) try self.updateLazySymbol(lazy_sym, symbol_index); |
| 2597 | return symbol_index; | 2521 | return symbol_index; |
| 2598 | } | 2522 | } |
| 2599 | | 2523 | |
| ... | @@ -2602,35 +2526,37 @@ pub fn getOrCreateMetadataForDecl(self: *Elf, decl_index: Module.Decl.Index) !Sy | ... | @@ -2602,35 +2526,37 @@ pub fn getOrCreateMetadataForDecl(self: *Elf, decl_index: Module.Decl.Index) !Sy |
| 2602 | if (!gop.found_existing) { | 2526 | if (!gop.found_existing) { |
| 2603 | const zig_module = self.file(self.zig_module_index.?).?.zig_module; | 2527 | const zig_module = self.file(self.zig_module_index.?).?.zig_module; |
| 2604 | gop.value_ptr.* = .{ | 2528 | gop.value_ptr.* = .{ |
| 2605 | .symbol_index = try zig_module.addAtom(self.getDeclShdrIndex(decl_index), self), | 2529 | .symbol_index = try zig_module.addAtom(self), |
| 2606 | .exports = .{}, | 2530 | .exports = .{}, |
| 2607 | }; | 2531 | }; |
| 2608 | } | 2532 | } |
| 2609 | return gop.value_ptr.symbol_index; | 2533 | return gop.value_ptr.symbol_index; |
| 2610 | } | 2534 | } |
| 2611 | | 2535 | |
| 2612 | fn getDeclShdrIndex(self: *Elf, decl_index: Module.Decl.Index) u16 { | 2536 | fn getDeclShdrIndex(self: *Elf, decl_index: Module.Decl.Index, code: []const u8) u16 { |
| 2613 | const mod = self.base.options.module.?; | 2537 | const mod = self.base.options.module.?; |
| 2614 | const decl = mod.declPtr(decl_index); | 2538 | const decl = mod.declPtr(decl_index); |
| 2615 | const ty = decl.ty; | 2539 | const shdr_index = switch (decl.ty.zigTypeTag(mod)) { |
| 2616 | const zig_ty = ty.zigTypeTag(mod); | 2540 | // TODO: what if this is a function pointer? |
| 2617 | const val = decl.val; | 2541 | .Fn => self.text_section_index.?, |
| 2618 | const shdr_index: u16 = blk: { | 2542 | else => blk: { |
| 2619 | if (val.isUndefDeep(mod)) { | 2543 | if (decl.getOwnedVariable(mod)) |variable| { |
| 2620 | // TODO in release-fast and release-small, we should put undef in .bss | 2544 | if (variable.is_const) break :blk self.rodata_section_index.?; |
| 2621 | break :blk self.data_section_index.?; | 2545 | if (variable.init.toValue().isUndefDeep(mod)) { |
| 2622 | } | 2546 | const mode = self.base.options.optimize_mode; |
| 2623 | | 2547 | if (mode == .Debug or mode == .ReleaseSafe) break :blk self.data_section_index.?; |
| 2624 | switch (zig_ty) { | 2548 | break :blk self.bss_section_index.?; |
| 2625 | // TODO: what if this is a function pointer? | | |
| 2626 | .Fn => break :blk self.text_section_index.?, | | |
| 2627 | else => { | | |
| 2628 | if (val.getVariable(mod)) |_| { | | |
| 2629 | break :blk self.data_section_index.?; | | |
| 2630 | } | 2549 | } |
| 2631 | break :blk self.rodata_section_index.?; | 2550 | // TODO I blatantly copied the logic from the Wasm linker, but is there a less |
| 2632 | }, | 2551 | // intrusive check for all zeroes than this? |
| 2633 | } | 2552 | const is_all_zeroes = for (code) |byte| { |
| | 2553 | if (byte != 0) break false; |
| | 2554 | } else true; |
| | 2555 | if (is_all_zeroes) break :blk self.bss_section_index.?; |
| | 2556 | break :blk self.data_section_index.?; |
| | 2557 | } |
| | 2558 | break :blk self.rodata_section_index.?; |
| | 2559 | }, |
| 2634 | }; | 2560 | }; |
| 2635 | return shdr_index; | 2561 | return shdr_index; |
| 2636 | } | 2562 | } |
| ... | @@ -2655,7 +2581,10 @@ fn updateDeclCode( | ... | @@ -2655,7 +2581,10 @@ fn updateDeclCode( |
| 2655 | const sym = self.symbol(sym_index); | 2581 | const sym = self.symbol(sym_index); |
| 2656 | const esym = &zig_module.local_esyms.items[sym.esym_index]; | 2582 | const esym = &zig_module.local_esyms.items[sym.esym_index]; |
| 2657 | const atom_ptr = sym.atom(self).?; | 2583 | const atom_ptr = sym.atom(self).?; |
| 2658 | const shdr_index = sym.output_section_index; | 2584 | |
| | 2585 | const shdr_index = self.getDeclShdrIndex(decl_index, code); |
| | 2586 | sym.output_section_index = shdr_index; |
| | 2587 | atom_ptr.output_section_index = shdr_index; |
| 2659 | | 2588 | |
| 2660 | sym.name_offset = try self.strtab.insert(gpa, decl_name); | 2589 | sym.name_offset = try self.strtab.insert(gpa, decl_name); |
| 2661 | atom_ptr.alive = true; | 2590 | atom_ptr.alive = true; |
| ... | @@ -2908,9 +2837,14 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. | ... | @@ -2908,9 +2837,14 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 2908 | }, | 2837 | }, |
| 2909 | }; | 2838 | }; |
| 2910 | | 2839 | |
| | 2840 | const output_section_index = switch (sym.kind) { |
| | 2841 | .code => self.text_section_index.?, |
| | 2842 | .const_data => self.rodata_section_index.?, |
| | 2843 | }; |
| 2911 | const local_sym = self.symbol(symbol_index); | 2844 | const local_sym = self.symbol(symbol_index); |
| 2912 | const phdr_index = self.phdr_to_shdr_table.get(local_sym.output_section_index).?; | 2845 | const phdr_index = self.phdr_to_shdr_table.get(output_section_index).?; |
| 2913 | local_sym.name_offset = name_str_index; | 2846 | local_sym.name_offset = name_str_index; |
| | 2847 | local_sym.output_section_index = output_section_index; |
| 2914 | const local_esym = &zig_module.local_esyms.items[local_sym.esym_index]; | 2848 | const local_esym = &zig_module.local_esyms.items[local_sym.esym_index]; |
| 2915 | local_esym.st_name = name_str_index; | 2849 | local_esym.st_name = name_str_index; |
| 2916 | local_esym.st_info |= elf.STT_OBJECT; | 2850 | local_esym.st_info |= elf.STT_OBJECT; |
| ... | @@ -2920,6 +2854,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. | ... | @@ -2920,6 +2854,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 2920 | atom_ptr.name_offset = name_str_index; | 2854 | atom_ptr.name_offset = name_str_index; |
| 2921 | atom_ptr.alignment = required_alignment; | 2855 | atom_ptr.alignment = required_alignment; |
| 2922 | atom_ptr.size = code.len; | 2856 | atom_ptr.size = code.len; |
| | 2857 | atom_ptr.output_section_index = output_section_index; |
| 2923 | | 2858 | |
| 2924 | try atom_ptr.allocate(self); | 2859 | try atom_ptr.allocate(self); |
| 2925 | errdefer self.freeDeclMetadata(symbol_index); | 2860 | errdefer self.freeDeclMetadata(symbol_index); |
| ... | @@ -2938,7 +2873,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. | ... | @@ -2938,7 +2873,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 2938 | try self.got.writeEntry(self, gop.index); | 2873 | try self.got.writeEntry(self, gop.index); |
| 2939 | | 2874 | |
| 2940 | const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr; | 2875 | const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr; |
| 2941 | const file_offset = self.shdrs.items[local_sym.output_section_index].sh_offset + section_offset; | 2876 | const file_offset = self.shdrs.items[output_section_index].sh_offset + section_offset; |
| 2942 | try self.base.file.?.pwriteAll(code, file_offset); | 2877 | try self.base.file.?.pwriteAll(code, file_offset); |
| 2943 | } | 2878 | } |
| 2944 | | 2879 | |
| ... | @@ -2966,7 +2901,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module | ... | @@ -2966,7 +2901,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 2966 | const name = self.strtab.get(name_str_index).?; | 2901 | const name = self.strtab.get(name_str_index).?; |
| 2967 | | 2902 | |
| 2968 | const zig_module = self.file(self.zig_module_index.?).?.zig_module; | 2903 | const zig_module = self.file(self.zig_module_index.?).?.zig_module; |
| 2969 | const sym_index = try zig_module.addAtom(self.rodata_section_index.?, self); | 2904 | const sym_index = try zig_module.addAtom(self); |
| 2970 | | 2905 | |
| 2971 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), typed_value, &code_buffer, .{ | 2906 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), typed_value, &code_buffer, .{ |
| 2972 | .none = {}, | 2907 | .none = {}, |
| ... | @@ -2988,6 +2923,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module | ... | @@ -2988,6 +2923,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 2988 | const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?; | 2923 | const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?; |
| 2989 | const local_sym = self.symbol(sym_index); | 2924 | const local_sym = self.symbol(sym_index); |
| 2990 | local_sym.name_offset = name_str_index; | 2925 | local_sym.name_offset = name_str_index; |
| | 2926 | local_sym.output_section_index = self.rodata_section_index.?; |
| 2991 | const local_esym = &zig_module.local_esyms.items[local_sym.esym_index]; | 2927 | const local_esym = &zig_module.local_esyms.items[local_sym.esym_index]; |
| 2992 | local_esym.st_name = name_str_index; | 2928 | local_esym.st_name = name_str_index; |
| 2993 | local_esym.st_info |= elf.STT_OBJECT; | 2929 | local_esym.st_info |= elf.STT_OBJECT; |
| ... | @@ -2997,6 +2933,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module | ... | @@ -2997,6 +2933,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 2997 | atom_ptr.name_offset = name_str_index; | 2933 | atom_ptr.name_offset = name_str_index; |
| 2998 | atom_ptr.alignment = required_alignment; | 2934 | atom_ptr.alignment = required_alignment; |
| 2999 | atom_ptr.size = code.len; | 2935 | atom_ptr.size = code.len; |
| | 2936 | atom_ptr.output_section_index = self.rodata_section_index.?; |
| 3000 | | 2937 | |
| 3001 | try atom_ptr.allocate(self); | 2938 | try atom_ptr.allocate(self); |
| 3002 | errdefer self.freeDeclMetadata(sym_index); | 2939 | errdefer self.freeDeclMetadata(sym_index); |
| ... | @@ -4014,6 +3951,54 @@ fn reportParseError( | ... | @@ -4014,6 +3951,54 @@ fn reportParseError( |
| 4014 | }); | 3951 | }); |
| 4015 | } | 3952 | } |
| 4016 | | 3953 | |
| | 3954 | fn fmtShdrs(self: *Elf) std.fmt.Formatter(formatShdrs) { |
| | 3955 | return .{ .data = self }; |
| | 3956 | } |
| | 3957 | |
| | 3958 | fn formatShdrs( |
| | 3959 | self: *Elf, |
| | 3960 | comptime unused_fmt_string: []const u8, |
| | 3961 | options: std.fmt.FormatOptions, |
| | 3962 | writer: anytype, |
| | 3963 | ) !void { |
| | 3964 | _ = options; |
| | 3965 | _ = unused_fmt_string; |
| | 3966 | for (self.shdrs.items, 0..) |shdr, i| { |
| | 3967 | try writer.print("shdr({d}) : phdr({?d}) : {s} : @{x} ({x}) : align({x}) : size({x})\n", .{ |
| | 3968 | i, self.phdr_to_shdr_table.get(@intCast(i)), |
| | 3969 | self.shstrtab.getAssumeExists(shdr.sh_name), shdr.sh_offset, |
| | 3970 | shdr.sh_addr, shdr.sh_addralign, |
| | 3971 | shdr.sh_size, |
| | 3972 | }); |
| | 3973 | } |
| | 3974 | } |
| | 3975 | |
| | 3976 | fn fmtPhdrs(self: *Elf) std.fmt.Formatter(formatPhdrs) { |
| | 3977 | return .{ .data = self }; |
| | 3978 | } |
| | 3979 | |
| | 3980 | fn formatPhdrs( |
| | 3981 | self: *Elf, |
| | 3982 | comptime unused_fmt_string: []const u8, |
| | 3983 | options: std.fmt.FormatOptions, |
| | 3984 | writer: anytype, |
| | 3985 | ) !void { |
| | 3986 | _ = options; |
| | 3987 | _ = unused_fmt_string; |
| | 3988 | for (self.phdrs.items, 0..) |phdr, i| { |
| | 3989 | const write = phdr.p_flags & elf.PF_W != 0; |
| | 3990 | const read = phdr.p_flags & elf.PF_R != 0; |
| | 3991 | const exec = phdr.p_flags & elf.PF_X != 0; |
| | 3992 | var flags: [3]u8 = [_]u8{'_'} ** 3; |
| | 3993 | if (exec) flags[0] = 'X'; |
| | 3994 | if (write) flags[1] = 'W'; |
| | 3995 | if (read) flags[2] = 'R'; |
| | 3996 | try writer.print("phdr({d}) : {s} : @{x} ({x}) : align({x}) : filesz({x}) : memsz({x})\n", .{ |
| | 3997 | i, flags, phdr.p_offset, phdr.p_vaddr, phdr.p_align, phdr.p_filesz, phdr.p_memsz, |
| | 3998 | }); |
| | 3999 | } |
| | 4000 | } |
| | 4001 | |
| 4017 | fn dumpState(self: *Elf) std.fmt.Formatter(fmtDumpState) { | 4002 | fn dumpState(self: *Elf) std.fmt.Formatter(fmtDumpState) { |
| 4018 | return .{ .data = self }; | 4003 | return .{ .data = self }; |
| 4019 | } | 4004 | } |
| ... | @@ -4053,6 +4038,10 @@ fn fmtDumpState( | ... | @@ -4053,6 +4038,10 @@ fn fmtDumpState( |
| 4053 | try writer.print("{}\n", .{linker_defined.fmtSymtab(self)}); | 4038 | try writer.print("{}\n", .{linker_defined.fmtSymtab(self)}); |
| 4054 | } | 4039 | } |
| 4055 | try writer.print("{}\n", .{self.got.fmt(self)}); | 4040 | try writer.print("{}\n", .{self.got.fmt(self)}); |
| | 4041 | try writer.writeAll("Output shdrs\n"); |
| | 4042 | try writer.print("{}\n", .{self.fmtShdrs()}); |
| | 4043 | try writer.writeAll("Output phdrs\n"); |
| | 4044 | try writer.print("{}\n", .{self.fmtPhdrs()}); |
| 4056 | } | 4045 | } |
| 4057 | | 4046 | |
| 4058 | /// Binary search | 4047 | /// Binary search |