| ... | @@ -743,7 +743,7 @@ pub const Reloc = extern struct { | ... | @@ -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 | assert(elf.ehdrField(.type) != .REL); | 747 | assert(elf.ehdrField(.type) != .REL); |
| 748 | const loc_ni = reloc.loc.get(elf).ni; | 748 | const loc_ni = reloc.loc.get(elf).ni; |
| 749 | switch (loc_ni) { | 749 | switch (loc_ni) { |
| ... | @@ -766,7 +766,7 @@ pub const Reloc = extern struct { | ... | @@ -766,7 +766,7 @@ pub const Reloc = extern struct { |
| 766 | elf.targetLoad(&target_sym.value) +% @as(u64, @bitCast(reloc.addend)); | 766 | elf.targetLoad(&target_sym.value) +% @as(u64, @bitCast(reloc.addend)); |
| 767 | switch (elf.ehdrField(.machine)) { | 767 | switch (elf.ehdrField(.machine)) { |
| 768 | else => |machine| @panic(@tagName(machine)), | 768 | else => |machine| @panic(@tagName(machine)), |
| 769 | .X86_64 => switch (reloc.type.X86_64) { | 769 | .X86_64 => type: switch (reloc.type.X86_64) { |
| 770 | else => |kind| @panic(@tagName(kind)), | 770 | else => |kind| @panic(@tagName(kind)), |
| 771 | .@"64" => std.mem.writeInt( | 771 | .@"64" => std.mem.writeInt( |
| 772 | u64, | 772 | u64, |
| ... | @@ -852,6 +852,75 @@ pub const Reloc = extern struct { | ... | @@ -852,6 +852,75 @@ pub const Reloc = extern struct { |
| 852 | elf.targetLoad(&target_sym.size) +% @as(u64, @bitCast(reloc.addend)), | 852 | elf.targetLoad(&target_sym.size) +% @as(u64, @bitCast(reloc.addend)), |
| 853 | target_endian, | 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,7 +1243,7 @@ fn initHeaders( |
| 1174 | } | 1243 | } |
| 1175 | | 1244 | |
| 1176 | assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{ | 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 | .alignment = elf.mf.flags.block_size, | 1247 | .alignment = elf.mf.flags.block_size, |
| 1179 | .moved = true, | 1248 | .moved = true, |
| 1180 | .resized = true, | 1249 | .resized = true, |
| ... | @@ -1191,7 +1260,7 @@ fn initHeaders( | ... | @@ -1191,7 +1260,7 @@ fn initHeaders( |
| 1191 | elf.phdrs.items[rodata_phndx] = elf.ni.rodata; | 1260 | elf.phdrs.items[rodata_phndx] = elf.ni.rodata; |
| 1192 | | 1261 | |
| 1193 | assert(elf.ni.phdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{ | 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 | .alignment = addr_align, | 1264 | .alignment = addr_align, |
| 1196 | .moved = true, | 1265 | .moved = true, |
| 1197 | .resized = true, | 1266 | .resized = true, |
| ... | @@ -2123,7 +2192,7 @@ fn loadObject( | ... | @@ -2123,7 +2192,7 @@ fn loadObject( |
| 2123 | if (ehdr.machine != elf.ehdrField(.machine)) | 2192 | if (ehdr.machine != elf.ehdrField(.machine)) |
| 2124 | return diags.failParse(path, "bad machine", .{}); | 2193 | return diags.failParse(path, "bad machine", .{}); |
| 2125 | if (ehdr.shoff == 0 or ehdr.shnum <= 1) return; | 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 | return diags.failParse(path, "bad section header location", .{}); | 2196 | return diags.failParse(path, "bad section header location", .{}); |
| 2128 | if (ehdr.shentsize < @sizeOf(ElfN.Shdr)) | 2197 | if (ehdr.shentsize < @sizeOf(ElfN.Shdr)) |
| 2129 | return diags.failParse(path, "unsupported shentsize", .{}); | 2198 | return diags.failParse(path, "unsupported shentsize", .{}); |
| ... | @@ -2228,11 +2297,11 @@ fn loadObject( | ... | @@ -2228,11 +2297,11 @@ fn loadObject( |
| 2228 | si.* = .null; | 2297 | si.* = .null; |
| 2229 | const input_sym = try r.peekStruct(ElfN.Sym, target_endian); | 2298 | const input_sym = try r.peekStruct(ElfN.Sym, target_endian); |
| 2230 | try r.discardAll64(symtab.shdr.entsize); | 2299 | try r.discardAll64(symtab.shdr.entsize); |
| 2231 | if (input_sym.name >= strtab.len or input_sym.shndx == std.elf.SHN_UNDEF or | 2300 | if (input_sym.name >= strtab.len or input_sym.shndx >= ehdr.shnum) continue; |
| 2232 | input_sym.shndx >= ehdr.shnum) continue; | | |
| 2233 | switch (input_sym.info.type) { | 2301 | switch (input_sym.info.type) { |
| 2234 | .NOTYPE, .OBJECT, .FUNC => {}, | 2302 | .NOTYPE, .OBJECT, .FUNC => {}, |
| 2235 | .SECTION => { | 2303 | .SECTION => { |
| | 2304 | if (input_sym.shndx == std.elf.SHN_UNDEF) continue; |
| 2236 | const section = &sections[input_sym.shndx]; | 2305 | const section = &sections[input_sym.shndx]; |
| 2237 | if (input_sym.value == section.shdr.addr) si.* = section.si; | 2306 | if (input_sym.value == section.shdr.addr) si.* = section.si; |
| 2238 | continue; | 2307 | continue; |
| ... | @@ -2254,21 +2323,30 @@ fn loadObject( | ... | @@ -2254,21 +2323,30 @@ fn loadObject( |
| 2254 | switch (input_sym.info.bind) { | 2323 | switch (input_sym.info.bind) { |
| 2255 | else => {}, | 2324 | else => {}, |
| 2256 | .GLOBAL => { | 2325 | .GLOBAL => { |
| 2257 | const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad( | 2326 | const sym = @field(elf.symPtr(si.*), @tagName(class)); |
| 2258 | &@field(elf.symPtr(si.*), @tagName(class)).name, | 2327 | const gop = |
| 2259 | )); | 2328 | elf.globals.getOrPutAssumeCapacity(elf.targetLoad(&sym.name)); |
| 2260 | if (gop.found_existing) switch (elf.targetLoad( | 2329 | if (gop.found_existing) switch (input_sym.shndx) { |
| 2261 | switch (elf.symPtr(gop.value_ptr.*)) { | 2330 | std.elf.SHN_UNDEF => {}, |
| 2262 | inline else => |sym| &sym.info, | 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 | gop.value_ptr.* = si.*; | 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,7 +2415,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { |
| 2337 | const r = &fr.interface; | 2415 | const r = &fr.interface; |
| 2338 | | 2416 | |
| 2339 | log.debug("loadDso({f})", .{path.fmtEscapeString()}); | 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 | if (!std.mem.eql(u8, ident[0..std.elf.MAGIC.len], std.elf.MAGIC)) return error.BadMagic; | 2419 | if (!std.mem.eql(u8, ident[0..std.elf.MAGIC.len], std.elf.MAGIC)) return error.BadMagic; |
| 2342 | if (!std.mem.eql(u8, ident[std.elf.MAGIC.len..], elf.mf.contents[std.elf.MAGIC.len..ident.len])) | 2420 | if (!std.mem.eql(u8, ident[std.elf.MAGIC.len..], elf.mf.contents[std.elf.MAGIC.len..ident.len])) |
| 2343 | return diags.failParse(path, "bad ident", .{}); | 2421 | return diags.failParse(path, "bad ident", .{}); |
| ... | @@ -2621,7 +2699,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | ... | @@ -2621,7 +2699,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 2621 | }, | 2699 | }, |
| 2622 | }; | 2700 | }; |
| 2623 | assert(shndx < @intFromEnum(Symbol.Index.Shndx.LORESERVE)); | 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 | _, const shdr_node_size = elf.ni.shdr.location(&elf.mf).resolve(&elf.mf); | 2705 | _, const shdr_node_size = elf.ni.shdr.location(&elf.mf).resolve(&elf.mf); |
| ... | @@ -3720,6 +3798,14 @@ fn updateExportsInner( | ... | @@ -3720,6 +3798,14 @@ fn updateExportsInner( |
| 3720 | }, | 3798 | }, |
| 3721 | } | 3799 | } |
| 3722 | export_si.flushMoved(elf, value); | 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 | |