| ... | @@ -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 | }, |
| ... | @@ -1176,7 +1245,7 @@ fn initHeaders( | ... | @@ -1176,7 +1245,7 @@ fn initHeaders( |
| 1176 | } | 1245 | } |
| 1177 | | 1246 | |
| 1178 | assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{ | 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 | .alignment = elf.mf.flags.block_size, | 1249 | .alignment = elf.mf.flags.block_size, |
| 1181 | .moved = true, | 1250 | .moved = true, |
| 1182 | .resized = true, | 1251 | .resized = true, |
| ... | @@ -1193,7 +1262,7 @@ fn initHeaders( | ... | @@ -1193,7 +1262,7 @@ fn initHeaders( |
| 1193 | elf.phdrs.items[rodata_phndx] = elf.ni.rodata; | 1262 | elf.phdrs.items[rodata_phndx] = elf.ni.rodata; |
| 1194 | | 1263 | |
| 1195 | assert(elf.ni.phdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{ | 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 | .alignment = addr_align, | 1266 | .alignment = addr_align, |
| 1198 | .moved = true, | 1267 | .moved = true, |
| 1199 | .resized = true, | 1268 | .resized = true, |
| ... | @@ -2108,7 +2177,7 @@ fn loadObject( | ... | @@ -2108,7 +2177,7 @@ fn loadObject( |
| 2108 | if (ehdr.machine != elf.ehdrField(.machine)) | 2177 | if (ehdr.machine != elf.ehdrField(.machine)) |
| 2109 | return diags.failParse(path, "bad machine", .{}); | 2178 | return diags.failParse(path, "bad machine", .{}); |
| 2110 | if (ehdr.shoff == 0 or ehdr.shnum <= 1) return; | 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 | return diags.failParse(path, "bad section header location", .{}); | 2181 | return diags.failParse(path, "bad section header location", .{}); |
| 2113 | if (ehdr.shentsize < @sizeOf(ElfN.Shdr)) | 2182 | if (ehdr.shentsize < @sizeOf(ElfN.Shdr)) |
| 2114 | return diags.failParse(path, "unsupported shentsize", .{}); | 2183 | return diags.failParse(path, "unsupported shentsize", .{}); |
| ... | @@ -2213,11 +2282,11 @@ fn loadObject( | ... | @@ -2213,11 +2282,11 @@ fn loadObject( |
| 2213 | si.* = .null; | 2282 | si.* = .null; |
| 2214 | const input_sym = try r.peekStruct(ElfN.Sym, target_endian); | 2283 | const input_sym = try r.peekStruct(ElfN.Sym, target_endian); |
| 2215 | try r.discardAll64(symtab.shdr.entsize); | 2284 | try r.discardAll64(symtab.shdr.entsize); |
| 2216 | if (input_sym.name >= strtab.len or input_sym.shndx == std.elf.SHN_UNDEF or | 2285 | if (input_sym.name >= strtab.len or input_sym.shndx >= ehdr.shnum) continue; |
| 2217 | input_sym.shndx >= ehdr.shnum) continue; | | |
| 2218 | switch (input_sym.info.type) { | 2286 | switch (input_sym.info.type) { |
| 2219 | .NOTYPE, .OBJECT, .FUNC => {}, | 2287 | .NOTYPE, .OBJECT, .FUNC => {}, |
| 2220 | .SECTION => { | 2288 | .SECTION => { |
| | 2289 | if (input_sym.shndx == std.elf.SHN_UNDEF) continue; |
| 2221 | const section = &sections[input_sym.shndx]; | 2290 | const section = &sections[input_sym.shndx]; |
| 2222 | if (input_sym.value == section.shdr.addr) si.* = section.si; | 2291 | if (input_sym.value == section.shdr.addr) si.* = section.si; |
| 2223 | continue; | 2292 | continue; |
| ... | @@ -2239,21 +2308,30 @@ fn loadObject( | ... | @@ -2239,21 +2308,30 @@ fn loadObject( |
| 2239 | switch (input_sym.info.bind) { | 2308 | switch (input_sym.info.bind) { |
| 2240 | else => {}, | 2309 | else => {}, |
| 2241 | .GLOBAL => { | 2310 | .GLOBAL => { |
| 2242 | const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad( | 2311 | const sym = @field(elf.symPtr(si.*), @tagName(class)); |
| 2243 | &@field(elf.symPtr(si.*), @tagName(class)).name, | 2312 | const gop = |
| 2244 | )); | 2313 | elf.globals.getOrPutAssumeCapacity(elf.targetLoad(&sym.name)); |
| 2245 | if (gop.found_existing) switch (elf.targetLoad( | 2314 | if (gop.found_existing) switch (input_sym.shndx) { |
| 2246 | switch (elf.symPtr(gop.value_ptr.*)) { | 2315 | std.elf.SHN_UNDEF => {}, |
| 2247 | inline else => |sym| &sym.info, | 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 | gop.value_ptr.* = si.*; | 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,7 +2400,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { |
| 2322 | const r = &fr.interface; | 2400 | const r = &fr.interface; |
| 2323 | | 2401 | |
| 2324 | log.debug("loadDso({f})", .{path.fmtEscapeString()}); | 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 | if (!std.mem.eql(u8, ident[0..std.elf.MAGIC.len], std.elf.MAGIC)) return error.BadMagic; | 2404 | if (!std.mem.eql(u8, ident[0..std.elf.MAGIC.len], std.elf.MAGIC)) return error.BadMagic; |
| 2327 | if (!std.mem.eql(u8, ident[std.elf.MAGIC.len..], elf.mf.memory_map.memory[std.elf.MAGIC.len..ident.len])) | 2405 | if (!std.mem.eql(u8, ident[std.elf.MAGIC.len..], elf.mf.memory_map.memory[std.elf.MAGIC.len..ident.len])) |
| 2328 | return diags.failParse(path, "bad ident", .{}); | 2406 | return diags.failParse(path, "bad ident", .{}); |
| ... | @@ -2606,7 +2684,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | ... | @@ -2606,7 +2684,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 2606 | }, | 2684 | }, |
| 2607 | }; | 2685 | }; |
| 2608 | assert(shndx < @intFromEnum(Symbol.Index.Shndx.LORESERVE)); | 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 | _, const shdr_node_size = elf.ni.shdr.location(&elf.mf).resolve(&elf.mf); | 2690 | _, const shdr_node_size = elf.ni.shdr.location(&elf.mf).resolve(&elf.mf); |
| ... | @@ -3706,6 +3784,14 @@ fn updateExportsInner( | ... | @@ -3706,6 +3784,14 @@ fn updateExportsInner( |
| 3706 | }, | 3784 | }, |
| 3707 | } | 3785 | } |
| 3708 | export_si.flushMoved(elf, value); | 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 | |