| ... | ... | @@ -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 | }, |
| ... | ... | @@ -1174,7 +1243,7 @@ fn initHeaders( |
| 1174 | 1243 | } |
| 1175 | 1244 | |
| 1176 | 1245 | assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{ |
| 1177 | | .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum), |
| 1246 | .size = @as(u64, elf.ehdrField(.shentsize)) * elf.ehdrField(.shnum), |
| 1178 | 1247 | .alignment = elf.mf.flags.block_size, |
| 1179 | 1248 | .moved = true, |
| 1180 | 1249 | .resized = true, |
| ... | ... | @@ -1191,7 +1260,7 @@ fn initHeaders( |
| 1191 | 1260 | elf.phdrs.items[rodata_phndx] = elf.ni.rodata; |
| 1192 | 1261 | |
| 1193 | 1262 | assert(elf.ni.phdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{ |
| 1194 | | .size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum), |
| 1263 | .size = @as(u64, elf.ehdrField(.phentsize)) * elf.ehdrField(.phnum), |
| 1195 | 1264 | .alignment = addr_align, |
| 1196 | 1265 | .moved = true, |
| 1197 | 1266 | .resized = true, |
| ... | ... | @@ -2123,7 +2192,7 @@ fn loadObject( |
| 2123 | 2192 | if (ehdr.machine != elf.ehdrField(.machine)) |
| 2124 | 2193 | return diags.failParse(path, "bad machine", .{}); |
| 2125 | 2194 | if (ehdr.shoff == 0 or ehdr.shnum <= 1) return; |
| 2126 | | if (ehdr.shoff + ehdr.shentsize * ehdr.shnum > fl.size) |
| 2195 | if (ehdr.shoff + @as(ElfN.Off, ehdr.shentsize) * ehdr.shnum > fl.size) |
| 2127 | 2196 | return diags.failParse(path, "bad section header location", .{}); |
| 2128 | 2197 | if (ehdr.shentsize < @sizeOf(ElfN.Shdr)) |
| 2129 | 2198 | return diags.failParse(path, "unsupported shentsize", .{}); |
| ... | ... | @@ -2228,11 +2297,11 @@ fn loadObject( |
| 2228 | 2297 | si.* = .null; |
| 2229 | 2298 | const input_sym = try r.peekStruct(ElfN.Sym, target_endian); |
| 2230 | 2299 | try r.discardAll64(symtab.shdr.entsize); |
| 2231 | | if (input_sym.name >= strtab.len or input_sym.shndx == std.elf.SHN_UNDEF or |
| 2232 | | input_sym.shndx >= ehdr.shnum) continue; |
| 2300 | if (input_sym.name >= strtab.len or input_sym.shndx >= ehdr.shnum) continue; |
| 2233 | 2301 | switch (input_sym.info.type) { |
| 2234 | 2302 | .NOTYPE, .OBJECT, .FUNC => {}, |
| 2235 | 2303 | .SECTION => { |
| 2304 | if (input_sym.shndx == std.elf.SHN_UNDEF) continue; |
| 2236 | 2305 | const section = &sections[input_sym.shndx]; |
| 2237 | 2306 | if (input_sym.value == section.shdr.addr) si.* = section.si; |
| 2238 | 2307 | continue; |
| ... | ... | @@ -2254,21 +2323,30 @@ fn loadObject( |
| 2254 | 2323 | switch (input_sym.info.bind) { |
| 2255 | 2324 | else => {}, |
| 2256 | 2325 | .GLOBAL => { |
| 2257 | | const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad( |
| 2258 | | &@field(elf.symPtr(si.*), @tagName(class)).name, |
| 2259 | | )); |
| 2260 | | if (gop.found_existing) switch (elf.targetLoad( |
| 2261 | | switch (elf.symPtr(gop.value_ptr.*)) { |
| 2262 | | inline else => |sym| &sym.info, |
| 2326 | const sym = @field(elf.symPtr(si.*), @tagName(class)); |
| 2327 | const gop = |
| 2328 | elf.globals.getOrPutAssumeCapacity(elf.targetLoad(&sym.name)); |
| 2329 | if (gop.found_existing) switch (input_sym.shndx) { |
| 2330 | std.elf.SHN_UNDEF => {}, |
| 2331 | else => { |
| 2332 | const existing_sym = |
| 2333 | @field(elf.symPtr(gop.value_ptr.*), @tagName(class)); |
| 2334 | switch (elf.targetLoad(&existing_sym.info).bind) { |
| 2335 | else => unreachable, |
| 2336 | .GLOBAL => switch (elf.targetLoad(&existing_sym.shndx)) { |
| 2337 | std.elf.SHN_UNDEF => {}, |
| 2338 | else => return diags.failParse( |
| 2339 | path, |
| 2340 | "multiple definitions of '{s}'", |
| 2341 | .{name}, |
| 2342 | ), |
| 2343 | }, |
| 2344 | .WEAK => {}, |
| 2345 | } |
| 2346 | existing_sym.size = sym.size; |
| 2347 | existing_sym.shndx = sym.shndx; |
| 2348 | gop.value_ptr.flushMoved(elf, input_sym.value); |
| 2263 | 2349 | }, |
| 2264 | | ).bind) { |
| 2265 | | else => unreachable, |
| 2266 | | .GLOBAL => return diags.failParse( |
| 2267 | | path, |
| 2268 | | "multiple definitions of '{s}'", |
| 2269 | | .{name}, |
| 2270 | | ), |
| 2271 | | .WEAK => {}, |
| 2272 | 2350 | }; |
| 2273 | 2351 | gop.value_ptr.* = si.*; |
| 2274 | 2352 | }, |
| ... | ... | @@ -2337,7 +2415,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { |
| 2337 | 2415 | const r = &fr.interface; |
| 2338 | 2416 | |
| 2339 | 2417 | log.debug("loadDso({f})", .{path.fmtEscapeString()}); |
| 2340 | | const ident = try r.peek(std.elf.EI.NIDENT); |
| 2418 | const ident = try r.peek(std.elf.EI.OSABI); |
| 2341 | 2419 | if (!std.mem.eql(u8, ident[0..std.elf.MAGIC.len], std.elf.MAGIC)) return error.BadMagic; |
| 2342 | 2420 | if (!std.mem.eql(u8, ident[std.elf.MAGIC.len..], elf.mf.contents[std.elf.MAGIC.len..ident.len])) |
| 2343 | 2421 | return diags.failParse(path, "bad ident", .{}); |
| ... | ... | @@ -2621,7 +2699,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 2621 | 2699 | }, |
| 2622 | 2700 | }; |
| 2623 | 2701 | assert(shndx < @intFromEnum(Symbol.Index.Shndx.LORESERVE)); |
| 2624 | | break :shndx .{ @enumFromInt(shndx), elf.targetLoad(&ehdr.shentsize) * shnum }; |
| 2702 | break :shndx .{ @enumFromInt(shndx), @as(u64, elf.targetLoad(&ehdr.shentsize)) * shnum }; |
| 2625 | 2703 | }, |
| 2626 | 2704 | }; |
| 2627 | 2705 | _, const shdr_node_size = elf.ni.shdr.location(&elf.mf).resolve(&elf.mf); |
| ... | ... | @@ -3720,6 +3798,14 @@ fn updateExportsInner( |
| 3720 | 3798 | }, |
| 3721 | 3799 | } |
| 3722 | 3800 | export_si.flushMoved(elf, value); |
| 3801 | if (elf.dynsym.getIndex(export_si)) |export_dsi| switch (elf.dynsymSlice()) { |
| 3802 | inline else => |dynsyms| { |
| 3803 | const dynsym = &dynsyms[export_dsi]; |
| 3804 | elf.targetStore(&dynsym.value, @intCast(value)); |
| 3805 | dynsym.size = @intCast(size); |
| 3806 | dynsym.shndx = shndx; |
| 3807 | }, |
| 3808 | }; |
| 3723 | 3809 | } |
| 3724 | 3810 | } |
| 3725 | 3811 | |