| ... | ... | @@ -174,7 +174,7 @@ const Update = struct { |
| 174 | 174 | if (program_header.p_offset <= start) continue; |
| 175 | 175 | if (program_header.p_offset < min_pos) min_pos = program_header.p_offset; |
| 176 | 176 | } |
| 177 | | return min_pos; |
| 177 | return min_pos - start; |
| 178 | 178 | } |
| 179 | 179 | |
| 180 | 180 | fn findFreeSpace(self: *Update, object_size: u64, min_alignment: u16) u64 { |
| ... | ... | @@ -233,7 +233,7 @@ const Update = struct { |
| 233 | 233 | // There must always be a null section in index 0 |
| 234 | 234 | try self.sections.append(.{ |
| 235 | 235 | .sh_name = 0, |
| 236 | | .sh_type = 0, |
| 236 | .sh_type = elf.SHT_NULL, |
| 237 | 237 | .sh_flags = 0, |
| 238 | 238 | .sh_addr = 0, |
| 239 | 239 | .sh_offset = 0, |
| ... | ... | @@ -247,6 +247,8 @@ const Update = struct { |
| 247 | 247 | } |
| 248 | 248 | if (self.shstrtab_index == null) { |
| 249 | 249 | self.shstrtab_index = @intCast(u16, self.sections.items.len); |
| 250 | assert(self.shstrtab.items.len == 0); |
| 251 | try self.shstrtab.append(0); // need a 0 at position 0 |
| 250 | 252 | const off = self.findFreeSpace(self.shstrtab.items.len, 1); |
| 251 | 253 | //std.debug.warn("found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len }); |
| 252 | 254 | try self.sections.append(.{ |
| ... | ... | @@ -299,7 +301,6 @@ const Update = struct { |
| 299 | 301 | .sh_size = file_size, |
| 300 | 302 | // The section header index of the associated string table. |
| 301 | 303 | .sh_link = self.shstrtab_index.?, |
| 302 | | // One greater than the symbol table index of the last local symbol (binding STB_LOCAL). |
| 303 | 304 | .sh_info = @intCast(u32, self.module.exports.len), |
| 304 | 305 | .sh_addralign = min_align, |
| 305 | 306 | .sh_entsize = each_size, |
| ... | ... | @@ -332,136 +333,105 @@ const Update = struct { |
| 332 | 333 | phdr_table_dirty = true; |
| 333 | 334 | } |
| 334 | 335 | const foreign_endian = self.module.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); |
| 335 | | if (shdr_table_dirty) { |
| 336 | | const allocated_size = self.allocatedSize(self.shdr_table_offset.?); |
| 337 | | const needed_size = self.sections.items.len * phsize; |
| 336 | |
| 337 | try self.writeCodeAndSymbols(phdr_table_dirty, shdr_table_dirty); |
| 338 | |
| 339 | if (phdr_table_dirty) { |
| 340 | const allocated_size = self.allocatedSize(self.phdr_table_offset.?); |
| 341 | const needed_size = self.program_headers.items.len * phsize; |
| 338 | 342 | |
| 339 | 343 | if (needed_size > allocated_size) { |
| 340 | | self.shdr_table_offset = null; // free the space |
| 341 | | self.shdr_table_offset = self.findFreeSpace(needed_size, phalign); |
| 344 | self.phdr_table_offset = null; // free the space |
| 345 | self.phdr_table_offset = self.findFreeSpace(needed_size, phalign); |
| 342 | 346 | } |
| 343 | 347 | |
| 344 | | const allocator = self.sections.allocator; |
| 348 | const allocator = self.program_headers.allocator; |
| 345 | 349 | switch (ptr_width) { |
| 346 | 350 | .p32 => { |
| 347 | | const buf = try allocator.alloc(elf.Elf32_Shdr, self.sections.items.len); |
| 351 | const buf = try allocator.alloc(elf.Elf32_Phdr, self.program_headers.items.len); |
| 348 | 352 | defer allocator.free(buf); |
| 349 | 353 | |
| 350 | | for (buf) |*shdr, i| { |
| 351 | | shdr.* = .{ |
| 352 | | .sh_name = self.sections.items[i].sh_name, |
| 353 | | .sh_type = self.sections.items[i].sh_type, |
| 354 | | .sh_flags = @intCast(u32, self.sections.items[i].sh_flags), |
| 355 | | .sh_addr = @intCast(u32, self.sections.items[i].sh_addr), |
| 356 | | .sh_offset = @intCast(u32, self.sections.items[i].sh_offset), |
| 357 | | .sh_size = @intCast(u32, self.sections.items[i].sh_size), |
| 358 | | .sh_link = self.sections.items[i].sh_link, |
| 359 | | .sh_info = self.sections.items[i].sh_info, |
| 360 | | .sh_addralign = @intCast(u32, self.sections.items[i].sh_addralign), |
| 361 | | .sh_entsize = @intCast(u32, self.sections.items[i].sh_entsize), |
| 362 | | }; |
| 354 | for (buf) |*phdr, i| { |
| 355 | phdr.* = progHeaderTo32(self.program_headers.items[i]); |
| 363 | 356 | if (foreign_endian) { |
| 364 | | bswapAllFields(elf.Elf32_Shdr, shdr); |
| 357 | bswapAllFields(elf.Elf32_Phdr, phdr); |
| 365 | 358 | } |
| 366 | 359 | } |
| 367 | | try self.file.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?); |
| 360 | try self.file.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?); |
| 368 | 361 | }, |
| 369 | 362 | .p64 => { |
| 370 | | const buf = try allocator.alloc(elf.Elf64_Shdr, self.sections.items.len); |
| 363 | const buf = try allocator.alloc(elf.Elf64_Phdr, self.program_headers.items.len); |
| 371 | 364 | defer allocator.free(buf); |
| 372 | 365 | |
| 373 | | for (buf) |*shdr, i| { |
| 374 | | shdr.* = .{ |
| 375 | | .sh_name = self.sections.items[i].sh_name, |
| 376 | | .sh_type = self.sections.items[i].sh_type, |
| 377 | | .sh_flags = self.sections.items[i].sh_flags, |
| 378 | | .sh_addr = self.sections.items[i].sh_addr, |
| 379 | | .sh_offset = self.sections.items[i].sh_offset, |
| 380 | | .sh_size = self.sections.items[i].sh_size, |
| 381 | | .sh_link = self.sections.items[i].sh_link, |
| 382 | | .sh_info = self.sections.items[i].sh_info, |
| 383 | | .sh_addralign = self.sections.items[i].sh_addralign, |
| 384 | | .sh_entsize = self.sections.items[i].sh_entsize, |
| 385 | | }; |
| 366 | for (buf) |*phdr, i| { |
| 367 | phdr.* = self.program_headers.items[i]; |
| 386 | 368 | if (foreign_endian) { |
| 387 | | bswapAllFields(elf.Elf64_Shdr, shdr); |
| 369 | bswapAllFields(elf.Elf64_Phdr, phdr); |
| 388 | 370 | } |
| 389 | 371 | } |
| 390 | | try self.file.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?); |
| 372 | try self.file.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?); |
| 391 | 373 | }, |
| 392 | 374 | } |
| 393 | 375 | } |
| 394 | 376 | |
| 395 | | try self.writeCodeAndSymbols(&phdr_table_dirty); |
| 377 | { |
| 378 | const shstrtab_sect = &self.sections.items[self.shstrtab_index.?]; |
| 379 | if (shstrtab_dirty or self.shstrtab.items.len != shstrtab_sect.sh_size) { |
| 380 | const allocated_size = self.allocatedSize(shstrtab_sect.sh_offset); |
| 381 | const needed_size = self.shstrtab.items.len; |
| 382 | |
| 383 | if (needed_size > allocated_size) { |
| 384 | shstrtab_sect.sh_size = 0; // free the space |
| 385 | shstrtab_sect.sh_offset = self.findFreeSpace(needed_size, 1); |
| 386 | } |
| 387 | shstrtab_sect.sh_size = needed_size; |
| 388 | //std.debug.warn("shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size }); |
| 396 | 389 | |
| 397 | | if (phdr_table_dirty) { |
| 398 | | const allocated_size = self.allocatedSize(self.phdr_table_offset.?); |
| 399 | | const needed_size = self.program_headers.items.len * phsize; |
| 390 | try self.file.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset); |
| 391 | if (!shdr_table_dirty) { |
| 392 | // Then it won't get written with the others and we need to do it. |
| 393 | try self.writeSectHeader(self.shstrtab_index.?); |
| 394 | } |
| 395 | } |
| 396 | } |
| 397 | if (shdr_table_dirty) { |
| 398 | const allocated_size = self.allocatedSize(self.shdr_table_offset.?); |
| 399 | const needed_size = self.sections.items.len * phsize; |
| 400 | 400 | |
| 401 | 401 | if (needed_size > allocated_size) { |
| 402 | | self.phdr_table_offset = null; // free the space |
| 403 | | self.phdr_table_offset = self.findFreeSpace(needed_size, phalign); |
| 402 | self.shdr_table_offset = null; // free the space |
| 403 | self.shdr_table_offset = self.findFreeSpace(needed_size, phalign); |
| 404 | 404 | } |
| 405 | 405 | |
| 406 | | const allocator = self.program_headers.allocator; |
| 406 | const allocator = self.sections.allocator; |
| 407 | 407 | switch (ptr_width) { |
| 408 | 408 | .p32 => { |
| 409 | | const buf = try allocator.alloc(elf.Elf32_Phdr, self.program_headers.items.len); |
| 409 | const buf = try allocator.alloc(elf.Elf32_Shdr, self.sections.items.len); |
| 410 | 410 | defer allocator.free(buf); |
| 411 | 411 | |
| 412 | | for (buf) |*phdr, i| { |
| 413 | | phdr.* = .{ |
| 414 | | .p_type = self.program_headers.items[i].p_type, |
| 415 | | .p_flags = self.program_headers.items[i].p_flags, |
| 416 | | .p_offset = @intCast(u32, self.program_headers.items[i].p_offset), |
| 417 | | .p_vaddr = @intCast(u32, self.program_headers.items[i].p_vaddr), |
| 418 | | .p_paddr = @intCast(u32, self.program_headers.items[i].p_paddr), |
| 419 | | .p_filesz = @intCast(u32, self.program_headers.items[i].p_filesz), |
| 420 | | .p_memsz = @intCast(u32, self.program_headers.items[i].p_memsz), |
| 421 | | .p_align = @intCast(u32, self.program_headers.items[i].p_align), |
| 422 | | }; |
| 412 | for (buf) |*shdr, i| { |
| 413 | shdr.* = sectHeaderTo32(self.sections.items[i]); |
| 423 | 414 | if (foreign_endian) { |
| 424 | | bswapAllFields(elf.Elf32_Phdr, phdr); |
| 415 | bswapAllFields(elf.Elf32_Shdr, shdr); |
| 425 | 416 | } |
| 426 | 417 | } |
| 427 | | try self.file.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?); |
| 418 | try self.file.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?); |
| 428 | 419 | }, |
| 429 | 420 | .p64 => { |
| 430 | | const buf = try allocator.alloc(elf.Elf64_Phdr, self.program_headers.items.len); |
| 421 | const buf = try allocator.alloc(elf.Elf64_Shdr, self.sections.items.len); |
| 431 | 422 | defer allocator.free(buf); |
| 432 | 423 | |
| 433 | | for (buf) |*phdr, i| { |
| 434 | | phdr.* = .{ |
| 435 | | .p_type = self.program_headers.items[i].p_type, |
| 436 | | .p_flags = self.program_headers.items[i].p_flags, |
| 437 | | .p_offset = self.program_headers.items[i].p_offset, |
| 438 | | .p_vaddr = self.program_headers.items[i].p_vaddr, |
| 439 | | .p_paddr = self.program_headers.items[i].p_paddr, |
| 440 | | .p_filesz = self.program_headers.items[i].p_filesz, |
| 441 | | .p_memsz = self.program_headers.items[i].p_memsz, |
| 442 | | .p_align = self.program_headers.items[i].p_align, |
| 443 | | }; |
| 424 | for (buf) |*shdr, i| { |
| 425 | shdr.* = self.sections.items[i]; |
| 426 | //std.debug.warn("writing section {}\n", .{shdr.*}); |
| 444 | 427 | if (foreign_endian) { |
| 445 | | bswapAllFields(elf.Elf64_Phdr, phdr); |
| 428 | bswapAllFields(elf.Elf64_Shdr, shdr); |
| 446 | 429 | } |
| 447 | 430 | } |
| 448 | | try self.file.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?); |
| 431 | try self.file.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?); |
| 449 | 432 | }, |
| 450 | 433 | } |
| 451 | 434 | } |
| 452 | | |
| 453 | | const shstrtab_sect = &self.sections.items[self.shstrtab_index.?]; |
| 454 | | if (shstrtab_dirty or self.shstrtab.items.len != shstrtab_sect.sh_size) { |
| 455 | | const allocated_size = self.allocatedSize(shstrtab_sect.sh_offset); |
| 456 | | const needed_size = self.shstrtab.items.len; |
| 457 | | |
| 458 | | if (needed_size > allocated_size) { |
| 459 | | shstrtab_sect.sh_size = 0; // free the space |
| 460 | | shstrtab_sect.sh_offset = self.findFreeSpace(needed_size, 1); |
| 461 | | shstrtab_sect.sh_size = needed_size; |
| 462 | | } |
| 463 | | try self.file.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset); |
| 464 | | } |
| 465 | 435 | if (self.entry_addr == null) { |
| 466 | 436 | const msg = try std.fmt.allocPrint(self.errors.allocator, "no entry point found", .{}); |
| 467 | 437 | errdefer self.errors.allocator.free(msg); |
| ... | ... | @@ -592,7 +562,7 @@ const Update = struct { |
| 592 | 562 | try self.file.pwriteAll(hdr_buf[0..index], 0); |
| 593 | 563 | } |
| 594 | 564 | |
| 595 | | fn writeCodeAndSymbols(self: *Update, phdr_table_dirty: *bool) !void { |
| 565 | fn writeCodeAndSymbols(self: *Update, phdr_table_dirty: bool, shdr_table_dirty: bool) !void { |
| 596 | 566 | // index 0 is always a null symbol |
| 597 | 567 | try self.symbols.resize(1); |
| 598 | 568 | self.symbols.items[0] = .{ |
| ... | ... | @@ -606,6 +576,7 @@ const Update = struct { |
| 606 | 576 | |
| 607 | 577 | const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; |
| 608 | 578 | var vaddr: u64 = phdr.p_vaddr; |
| 579 | var file_off: u64 = phdr.p_offset; |
| 609 | 580 | |
| 610 | 581 | var code = std.ArrayList(u8).init(self.sections.allocator); |
| 611 | 582 | defer code.deinit(); |
| ... | ... | @@ -625,6 +596,7 @@ const Update = struct { |
| 625 | 596 | } |
| 626 | 597 | continue; |
| 627 | 598 | } |
| 599 | try self.file.pwriteAll(code.items, file_off); |
| 628 | 600 | |
| 629 | 601 | if (mem.eql(u8, exp.name, "_start")) { |
| 630 | 602 | self.entry_addr = vaddr; |
| ... | ... | @@ -645,12 +617,67 @@ const Update = struct { |
| 645 | 617 | phdr.p_memsz = vaddr - phdr.p_vaddr; |
| 646 | 618 | phdr.p_filesz = phdr.p_memsz; |
| 647 | 619 | |
| 648 | | phdr_table_dirty.* = true; |
| 620 | const shdr = &self.sections.items[self.text_section_index.?]; |
| 621 | shdr.sh_size = phdr.p_filesz; |
| 622 | |
| 623 | if (!phdr_table_dirty) { |
| 624 | // Then it won't get written with the others and we need to do it. |
| 625 | try self.writeProgHeader(self.phdr_load_re_index.?); |
| 626 | } |
| 627 | if (!shdr_table_dirty) { |
| 628 | // Then it won't get written with the others and we need to do it. |
| 629 | try self.writeSectHeader(self.text_section_index.?); |
| 630 | } |
| 649 | 631 | } |
| 650 | 632 | |
| 651 | 633 | return self.writeSymbols(); |
| 652 | 634 | } |
| 653 | 635 | |
| 636 | fn writeProgHeader(self: *Update, index: usize) !void { |
| 637 | const foreign_endian = self.module.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); |
| 638 | const offset = self.program_headers.items[index].p_offset; |
| 639 | switch (self.module.target.cpu.arch.ptrBitWidth()) { |
| 640 | 32 => { |
| 641 | var phdr = [1]elf.Elf32_Phdr{progHeaderTo32(self.program_headers.items[index])}; |
| 642 | if (foreign_endian) { |
| 643 | bswapAllFields(elf.Elf32_Phdr, &phdr[0]); |
| 644 | } |
| 645 | return self.file.pwriteAll(mem.sliceAsBytes(&phdr), offset); |
| 646 | }, |
| 647 | 64 => { |
| 648 | var phdr = [1]elf.Elf64_Phdr{self.program_headers.items[index]}; |
| 649 | if (foreign_endian) { |
| 650 | bswapAllFields(elf.Elf64_Phdr, &phdr[0]); |
| 651 | } |
| 652 | return self.file.pwriteAll(mem.sliceAsBytes(&phdr), offset); |
| 653 | }, |
| 654 | else => return error.UnsupportedArchitecture, |
| 655 | } |
| 656 | } |
| 657 | |
| 658 | fn writeSectHeader(self: *Update, index: usize) !void { |
| 659 | const foreign_endian = self.module.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); |
| 660 | const offset = self.sections.items[index].sh_offset; |
| 661 | switch (self.module.target.cpu.arch.ptrBitWidth()) { |
| 662 | 32 => { |
| 663 | var shdr: [1]elf.Elf32_Shdr = undefined; |
| 664 | shdr[0] = sectHeaderTo32(self.sections.items[index]); |
| 665 | if (foreign_endian) { |
| 666 | bswapAllFields(elf.Elf32_Shdr, &shdr[0]); |
| 667 | } |
| 668 | return self.file.pwriteAll(mem.sliceAsBytes(&shdr), offset); |
| 669 | }, |
| 670 | 64 => { |
| 671 | var shdr = [1]elf.Elf64_Shdr{self.sections.items[index]}; |
| 672 | if (foreign_endian) { |
| 673 | bswapAllFields(elf.Elf64_Shdr, &shdr[0]); |
| 674 | } |
| 675 | return self.file.pwriteAll(mem.sliceAsBytes(&shdr), offset); |
| 676 | }, |
| 677 | else => return error.UnsupportedArchitecture, |
| 678 | } |
| 679 | } |
| 680 | |
| 654 | 681 | fn writeSymbols(self: *Update) !void { |
| 655 | 682 | const ptr_width: enum { p32, p64 } = switch (self.module.target.cpu.arch.ptrBitWidth()) { |
| 656 | 683 | 32 => .p32, |
| ... | ... | @@ -667,8 +694,11 @@ const Update = struct { |
| 667 | 694 | if (needed_size > allocated_size) { |
| 668 | 695 | syms_sect.sh_size = 0; // free the space |
| 669 | 696 | syms_sect.sh_offset = self.findFreeSpace(needed_size, sym_align); |
| 670 | | syms_sect.sh_size = needed_size; |
| 697 | //std.debug.warn("moved symtab to 0x{x} to 0x{x}\n", .{ syms_sect.sh_offset, syms_sect.sh_offset + needed_size }); |
| 671 | 698 | } |
| 699 | //std.debug.warn("symtab start=0x{x} end=0x{x}\n", .{ syms_sect.sh_offset, syms_sect.sh_offset + needed_size }); |
| 700 | syms_sect.sh_size = needed_size; |
| 701 | syms_sect.sh_info = @intCast(u32, self.symbols.items.len); |
| 672 | 702 | const allocator = self.symbols.allocator; |
| 673 | 703 | const foreign_endian = self.module.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); |
| 674 | 704 | switch (ptr_width) { |
| ... | ... | @@ -760,3 +790,31 @@ fn satMul(a: var, b: var) @TypeOf(a, b) { |
| 760 | 790 | fn bswapAllFields(comptime S: type, ptr: *S) void { |
| 761 | 791 | @panic("TODO implement bswapAllFields"); |
| 762 | 792 | } |
| 793 | |
| 794 | fn progHeaderTo32(phdr: elf.Elf64_Phdr) elf.Elf32_Phdr { |
| 795 | return .{ |
| 796 | .p_type = phdr.p_type, |
| 797 | .p_flags = phdr.p_flags, |
| 798 | .p_offset = @intCast(u32, phdr.p_offset), |
| 799 | .p_vaddr = @intCast(u32, phdr.p_vaddr), |
| 800 | .p_paddr = @intCast(u32, phdr.p_paddr), |
| 801 | .p_filesz = @intCast(u32, phdr.p_filesz), |
| 802 | .p_memsz = @intCast(u32, phdr.p_memsz), |
| 803 | .p_align = @intCast(u32, phdr.p_align), |
| 804 | }; |
| 805 | } |
| 806 | |
| 807 | fn sectHeaderTo32(shdr: elf.Elf64_Shdr) elf.Elf32_Shdr { |
| 808 | return .{ |
| 809 | .sh_name = shdr.sh_name, |
| 810 | .sh_type = shdr.sh_type, |
| 811 | .sh_flags = @intCast(u32, shdr.sh_flags), |
| 812 | .sh_addr = @intCast(u32, shdr.sh_addr), |
| 813 | .sh_offset = @intCast(u32, shdr.sh_offset), |
| 814 | .sh_size = @intCast(u32, shdr.sh_size), |
| 815 | .sh_link = shdr.sh_link, |
| 816 | .sh_info = shdr.sh_info, |
| 817 | .sh_addralign = @intCast(u32, shdr.sh_addralign), |
| 818 | .sh_entsize = @intCast(u32, shdr.sh_entsize), |
| 819 | }; |
| 820 | } |