| ... | ... | @@ -743,7 +743,7 @@ pub const Reloc = extern struct { |
| 743 | 743 | } |
| 744 | 744 | }; |
| 745 | 745 | |
| 746 | | pub fn apply(reloc: *const Reloc, elf: *Elf) void { |
| 746 | pub fn apply(reloc: *Reloc, elf: *Elf) void { |
| 747 | 747 | assert(elf.ehdrField(.type) != .REL); |
| 748 | 748 | const loc_ni = reloc.loc.get(elf).ni; |
| 749 | 749 | switch (loc_ni) { |
| ... | ... | @@ -766,7 +766,7 @@ pub const Reloc = extern struct { |
| 766 | 766 | elf.targetLoad(&target_sym.value) +% @as(u64, @bitCast(reloc.addend)); |
| 767 | 767 | switch (elf.ehdrField(.machine)) { |
| 768 | 768 | else => |machine| @panic(@tagName(machine)), |
| 769 | | .X86_64 => switch (reloc.type.X86_64) { |
| 769 | .X86_64 => type: switch (reloc.type.X86_64) { |
| 770 | 770 | else => |kind| @panic(@tagName(kind)), |
| 771 | 771 | .@"64" => std.mem.writeInt( |
| 772 | 772 | u64, |
| ... | ... | @@ -852,6 +852,75 @@ pub const Reloc = extern struct { |
| 852 | 852 | elf.targetLoad(&target_sym.size) +% @as(u64, @bitCast(reloc.addend)), |
| 853 | 853 | target_endian, |
| 854 | 854 | ), |
| 855 | .GOTPCRELX => { |
| 856 | relax: switch (Symbol.Index.Shndx.fromSection( |
| 857 | elf.targetLoad(&target_sym.shndx), |
| 858 | )) { |
| 859 | .UNDEF => {}, |
| 860 | else => { |
| 861 | const inst = (loc_slice.ptr - 2)[0..2]; |
| 862 | if (inst[0] != 0xff) break :relax; |
| 863 | const mod_rm: packed struct { |
| 864 | rm: u3, |
| 865 | opcode: u3, |
| 866 | mod: u2, |
| 867 | } = @bitCast(inst[1]); |
| 868 | if (mod_rm.mod != 0b00) break :relax; |
| 869 | if (mod_rm.rm != 0b101) break :relax; |
| 870 | switch (mod_rm.opcode) { |
| 871 | 0, // incl 0x0(%rip) |
| 872 | 1, // decl 0x0(%rip) |
| 873 | 3, // lcall *0x0(%rip) |
| 874 | 5, // ljmp *0x0(%rip) |
| 875 | 6, // push 0x0(%rip) |
| 876 | 7, // ud 0x0(%rip) |
| 877 | => break :relax, |
| 878 | 2 => { // call *0x0(%rip) |
| 879 | inst[1] = 0xe8; // call 0 |
| 880 | }, |
| 881 | 4 => { // jmp *0x0(%rip) |
| 882 | inst[1] = 0xe9; // jmp 0 |
| 883 | }, |
| 884 | } |
| 885 | inst[0] = 0x48; // rex.W |
| 886 | reloc.type.X86_64 = .PC32; |
| 887 | continue :type .PC32; |
| 888 | }, |
| 889 | } |
| 890 | @panic("relax failure"); |
| 891 | }, |
| 892 | .REX_GOTPCRELX => { |
| 893 | relax: switch (Symbol.Index.Shndx.fromSection( |
| 894 | elf.targetLoad(&target_sym.shndx), |
| 895 | )) { |
| 896 | .UNDEF => {}, |
| 897 | else => { |
| 898 | const inst = (loc_slice.ptr - 3)[0..3]; |
| 899 | const rex: packed struct { |
| 900 | b: bool, |
| 901 | x: bool, |
| 902 | r: bool, |
| 903 | w: bool, |
| 904 | encoded4: u4, |
| 905 | } = @bitCast(inst[0]); |
| 906 | if (rex.encoded4 != 0b0100) break :relax; |
| 907 | if (!rex.w) break :relax; |
| 908 | if (rex.x) break :relax; |
| 909 | if (inst[1] != 0x8b) break :relax; // mov |
| 910 | const mod_rm: packed struct { |
| 911 | rm: u3, |
| 912 | r: u3, |
| 913 | mod: u2, |
| 914 | } = @bitCast(inst[2]); |
| 915 | if (mod_rm.mod != 0b00) break :relax; |
| 916 | if (mod_rm.rm != 0b101) break :relax; |
| 917 | inst[1] = 0x8d; // lea |
| 918 | reloc.type.X86_64 = .PC32; |
| 919 | continue :type .PC32; |
| 920 | }, |
| 921 | } |
| 922 | @panic("relax failure"); |
| 923 | }, |
| 855 | 924 | }, |
| 856 | 925 | } |
| 857 | 926 | }, |
| ... | ... | @@ -1176,7 +1245,7 @@ fn initHeaders( |
| 1176 | 1245 | } |
| 1177 | 1246 | |
| 1178 | 1247 | assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{ |
| 1179 | | .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum), |
| 1248 | .size = @as(u64, elf.ehdrField(.shentsize)) * elf.ehdrField(.shnum), |
| 1180 | 1249 | .alignment = elf.mf.flags.block_size, |
| 1181 | 1250 | .moved = true, |
| 1182 | 1251 | .resized = true, |
| ... | ... | @@ -1193,7 +1262,7 @@ fn initHeaders( |
| 1193 | 1262 | elf.phdrs.items[rodata_phndx] = elf.ni.rodata; |
| 1194 | 1263 | |
| 1195 | 1264 | assert(elf.ni.phdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{ |
| 1196 | | .size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum), |
| 1265 | .size = @as(u64, elf.ehdrField(.phentsize)) * elf.ehdrField(.phnum), |
| 1197 | 1266 | .alignment = addr_align, |
| 1198 | 1267 | .moved = true, |
| 1199 | 1268 | .resized = true, |
| ... | ... | @@ -2108,7 +2177,7 @@ fn loadObject( |
| 2108 | 2177 | if (ehdr.machine != elf.ehdrField(.machine)) |
| 2109 | 2178 | return diags.failParse(path, "bad machine", .{}); |
| 2110 | 2179 | if (ehdr.shoff == 0 or ehdr.shnum <= 1) return; |
| 2111 | | if (ehdr.shoff + ehdr.shentsize * ehdr.shnum > fl.size) |
| 2180 | if (ehdr.shoff + @as(ElfN.Off, ehdr.shentsize) * ehdr.shnum > fl.size) |
| 2112 | 2181 | return diags.failParse(path, "bad section header location", .{}); |
| 2113 | 2182 | if (ehdr.shentsize < @sizeOf(ElfN.Shdr)) |
| 2114 | 2183 | return diags.failParse(path, "unsupported shentsize", .{}); |
| ... | ... | @@ -2213,11 +2282,11 @@ fn loadObject( |
| 2213 | 2282 | si.* = .null; |
| 2214 | 2283 | const input_sym = try r.peekStruct(ElfN.Sym, target_endian); |
| 2215 | 2284 | try r.discardAll64(symtab.shdr.entsize); |
| 2216 | | if (input_sym.name >= strtab.len or input_sym.shndx == std.elf.SHN_UNDEF or |
| 2217 | | input_sym.shndx >= ehdr.shnum) continue; |
| 2285 | if (input_sym.name >= strtab.len or input_sym.shndx >= ehdr.shnum) continue; |
| 2218 | 2286 | switch (input_sym.info.type) { |
| 2219 | 2287 | .NOTYPE, .OBJECT, .FUNC => {}, |
| 2220 | 2288 | .SECTION => { |
| 2289 | if (input_sym.shndx == std.elf.SHN_UNDEF) continue; |
| 2221 | 2290 | const section = &sections[input_sym.shndx]; |
| 2222 | 2291 | if (input_sym.value == section.shdr.addr) si.* = section.si; |
| 2223 | 2292 | continue; |
| ... | ... | @@ -2239,21 +2308,30 @@ fn loadObject( |
| 2239 | 2308 | switch (input_sym.info.bind) { |
| 2240 | 2309 | else => {}, |
| 2241 | 2310 | .GLOBAL => { |
| 2242 | | const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad( |
| 2243 | | &@field(elf.symPtr(si.*), @tagName(class)).name, |
| 2244 | | )); |
| 2245 | | if (gop.found_existing) switch (elf.targetLoad( |
| 2246 | | switch (elf.symPtr(gop.value_ptr.*)) { |
| 2247 | | inline else => |sym| &sym.info, |
| 2311 | const sym = @field(elf.symPtr(si.*), @tagName(class)); |
| 2312 | const gop = |
| 2313 | elf.globals.getOrPutAssumeCapacity(elf.targetLoad(&sym.name)); |
| 2314 | if (gop.found_existing) switch (input_sym.shndx) { |
| 2315 | std.elf.SHN_UNDEF => {}, |
| 2316 | else => { |
| 2317 | const existing_sym = |
| 2318 | @field(elf.symPtr(gop.value_ptr.*), @tagName(class)); |
| 2319 | switch (elf.targetLoad(&existing_sym.info).bind) { |
| 2320 | else => unreachable, |
| 2321 | .GLOBAL => switch (elf.targetLoad(&existing_sym.shndx)) { |
| 2322 | std.elf.SHN_UNDEF => {}, |
| 2323 | else => return diags.failParse( |
| 2324 | path, |
| 2325 | "multiple definitions of '{s}'", |
| 2326 | .{name}, |
| 2327 | ), |
| 2328 | }, |
| 2329 | .WEAK => {}, |
| 2330 | } |
| 2331 | existing_sym.size = sym.size; |
| 2332 | existing_sym.shndx = sym.shndx; |
| 2333 | gop.value_ptr.flushMoved(elf, input_sym.value); |
| 2248 | 2334 | }, |
| 2249 | | ).bind) { |
| 2250 | | else => unreachable, |
| 2251 | | .GLOBAL => return diags.failParse( |
| 2252 | | path, |
| 2253 | | "multiple definitions of '{s}'", |
| 2254 | | .{name}, |
| 2255 | | ), |
| 2256 | | .WEAK => {}, |
| 2257 | 2335 | }; |
| 2258 | 2336 | gop.value_ptr.* = si.*; |
| 2259 | 2337 | }, |
| ... | ... | @@ -2322,7 +2400,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { |
| 2322 | 2400 | const r = &fr.interface; |
| 2323 | 2401 | |
| 2324 | 2402 | log.debug("loadDso({f})", .{path.fmtEscapeString()}); |
| 2325 | | const ident = try r.peek(std.elf.EI.NIDENT); |
| 2403 | const ident = try r.peek(std.elf.EI.OSABI); |
| 2326 | 2404 | if (!std.mem.eql(u8, ident[0..std.elf.MAGIC.len], std.elf.MAGIC)) return error.BadMagic; |
| 2327 | 2405 | if (!std.mem.eql(u8, ident[std.elf.MAGIC.len..], elf.mf.memory_map.memory[std.elf.MAGIC.len..ident.len])) |
| 2328 | 2406 | return diags.failParse(path, "bad ident", .{}); |
| ... | ... | @@ -2606,7 +2684,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 2606 | 2684 | }, |
| 2607 | 2685 | }; |
| 2608 | 2686 | assert(shndx < @intFromEnum(Symbol.Index.Shndx.LORESERVE)); |
| 2609 | | break :shndx .{ @enumFromInt(shndx), elf.targetLoad(&ehdr.shentsize) * shnum }; |
| 2687 | break :shndx .{ @enumFromInt(shndx), @as(u64, elf.targetLoad(&ehdr.shentsize)) * shnum }; |
| 2610 | 2688 | }, |
| 2611 | 2689 | }; |
| 2612 | 2690 | _, const shdr_node_size = elf.ni.shdr.location(&elf.mf).resolve(&elf.mf); |
| ... | ... | @@ -3706,6 +3784,14 @@ fn updateExportsInner( |
| 3706 | 3784 | }, |
| 3707 | 3785 | } |
| 3708 | 3786 | export_si.flushMoved(elf, value); |
| 3787 | if (elf.dynsym.getIndex(export_si)) |export_dsi| switch (elf.dynsymSlice()) { |
| 3788 | inline else => |dynsyms| { |
| 3789 | const dynsym = &dynsyms[export_dsi]; |
| 3790 | elf.targetStore(&dynsym.value, @intCast(value)); |
| 3791 | dynsym.size = @intCast(size); |
| 3792 | dynsym.shndx = shndx; |
| 3793 | }, |
| 3794 | }; |
| 3709 | 3795 | } |
| 3710 | 3796 | } |
| 3711 | 3797 | |