| ... | ... | @@ -100,13 +100,15 @@ dynstr: StringTable, |
| 100 | 100 | /// |
| 101 | 101 | /// Value is the output relocation in `.rela.dyn` for the GOT entry. |
| 102 | 102 | got: std.array_hash_map.Auto(GotKey, Section.RelaIndex.Optional), |
| 103 | /// Key is the name of a global. |
| 104 | /// |
| 103 | 105 | /// Indices map 1--1 to indices into the actual `.got.plt` section. These also equal indices into |
| 104 | 106 | /// the relocations in `.rela.plt`, because every PLT entry has one output relocation (if a runtime |
| 105 | 107 | /// relocation is no longer necessary, then neither is the corresponding PLT entry!). |
| 106 | 108 | /// |
| 107 | 109 | /// PLT entries in this map may be "dead", meaning the PLT entry has been deemed unnecessary so is |
| 108 | 110 | /// available for reuse---see `Elf.pltEntryIsDead`. Such entries must not be targeted by relocs. |
| 109 | | plt: std.array_hash_map.Auto(Symbol.Id, void), |
| 111 | plt: std.array_hash_map.Auto(String(.strtab), void), |
| 110 | 112 | /// The `.plt` section contains zero or more symbol relocations starting at this index. |
| 111 | 113 | plt_first_symbol_reloc: SymbolReloc.Index, |
| 112 | 114 | /// The `.dynamic` section contains zero or more symbol relocations starting at this index. |
| ... | ... | @@ -1126,7 +1128,10 @@ const SymbolReloc = struct { |
| 1126 | 1128 | target_endian, |
| 1127 | 1129 | ), |
| 1128 | 1130 | .pltrel64 => { |
| 1129 | | const plt_index = elf.plt.getIndex(reloc.target) orelse continue :type .rel64; |
| 1131 | const plt_index = switch (reloc.target.unwrap()) { |
| 1132 | .local => continue :type .rel64, |
| 1133 | .global => |name| elf.plt.getIndex(name) orelse continue :type .rel64, |
| 1134 | }; |
| 1130 | 1135 | if (elf.pltEntryIsDead(plt_index)) continue :type .rel64; |
| 1131 | 1136 | const plt_shndx: Section.Index, const plt_entry_size: u64 = switch (elf.ehdrField(.machine)) { |
| 1132 | 1137 | else => |machine| @panic(@tagName(machine)), |
| ... | ... | @@ -1141,7 +1146,10 @@ const SymbolReloc = struct { |
| 1141 | 1146 | ); |
| 1142 | 1147 | }, |
| 1143 | 1148 | .pltrel32 => { |
| 1144 | | const plt_index = elf.plt.getIndex(reloc.target) orelse continue :type .rel32; |
| 1149 | const plt_index = switch (reloc.target.unwrap()) { |
| 1150 | .local => continue :type .rel32, |
| 1151 | .global => |name| elf.plt.getIndex(name) orelse continue :type .rel32, |
| 1152 | }; |
| 1145 | 1153 | if (elf.pltEntryIsDead(plt_index)) continue :type .rel32; |
| 1146 | 1154 | const plt_shndx: Section.Index, const plt_entry_size: u64 = switch (elf.ehdrField(.machine)) { |
| 1147 | 1155 | else => |machine| @panic(@tagName(machine)), |
| ... | ... | @@ -1843,7 +1851,7 @@ fn setGlobalSymbolValue( |
| 1843 | 1851 | // If this symbol was previously undefined, it may have had a PLT entry. If so, we now need to |
| 1844 | 1852 | // delete its newly-unnecessary runtime relocation to avoid a runtime dynamic linker error. |
| 1845 | 1853 | // This also allows the PLT entry to be reused---see `pltEntryIsDead`. |
| 1846 | | if (elf.plt.getIndex(.global(global_name))) |plt_index| { |
| 1854 | if (elf.plt.getIndex(global_name)) |plt_index| { |
| 1847 | 1855 | // TODO: we might still need the PLT entry if the symbol could be preempted/interposed! See |
| 1848 | 1856 | // matching comment at the end of `addGlobalSymbolAssumeCapacity`. |
| 1849 | 1857 | if (!elf.pltEntryIsDead(plt_index)) { |
| ... | ... | @@ -2033,13 +2041,13 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void |
| 2033 | 2041 | |
| 2034 | 2042 | if (plt_index < elf.plt.count()) { |
| 2035 | 2043 | // We reused a free entry, so we're already done! |
| 2036 | | elf.plt.setKey(plt_index, .global(global_name)); |
| 2044 | elf.plt.setKey(plt_index, global_name); |
| 2037 | 2045 | return; |
| 2038 | 2046 | } |
| 2039 | 2047 | |
| 2040 | 2048 | // We added a new entry, so we now need to extend the PLT sections. |
| 2041 | 2049 | assert(plt_index == elf.plt.count()); |
| 2042 | | elf.plt.putAssumeCapacityNoClobber(.global(global_name), {}); |
| 2050 | elf.plt.putAssumeCapacityNoClobber(global_name, {}); |
| 2043 | 2051 | |
| 2044 | 2052 | switch (elf.ehdrField(.machine)) { |
| 2045 | 2053 | else => |machine| @panic(@tagName(machine)), |
| ... | ... | @@ -6995,8 +7003,8 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad |
| 6995 | 7003 | // its relocations are probably going through the PLT, so we don't bother with |
| 6996 | 7004 | // specific tracking for PLT relocations---instead just re-apply all relocations |
| 6997 | 7005 | // targeting symbols with PLT entries. |
| 6998 | | for (elf.plt.keys()) |sym| { |
| 6999 | | sym.applyTargetRelocs(elf); |
| 7006 | for (elf.plt.keys()) |name| { |
| 7007 | Symbol.Id.global(name).applyTargetRelocs(elf); |
| 7000 | 7008 | } |
| 7001 | 7009 | // We also need to update all of the references from `.plt.sec` to `.got.plt`. |
| 7002 | 7010 | // However, if there's also a flush pending for `.got.plt`, don't bother doing |