| ... | @@ -25,55 +25,102 @@ ni: Node.Known, | ... | @@ -25,55 +25,102 @@ ni: Node.Known, |
| 25 | nodes: std.MultiArrayList(Node), | 25 | nodes: std.MultiArrayList(Node), |
| 26 | shdrs: std.ArrayList(Section), | 26 | shdrs: std.ArrayList(Section), |
| 27 | phdrs: std.ArrayList(MappedFile.Node.Index), | 27 | phdrs: std.ArrayList(MappedFile.Node.Index), |
| 28 | si: Symbol.Known, | 28 | shndx: struct { |
| | 29 | got: Section.Index, |
| | 30 | got_plt: Section.Index, |
| | 31 | plt: Section.Index, |
| | 32 | plt_sec: Section.Index, |
| | 33 | dynsym: Section.Index, |
| | 34 | dynstr: Section.Index, |
| | 35 | dynamic: Section.Index, |
| | 36 | tdata: Section.Index, |
| | 37 | }, |
| 29 | symtab: std.ArrayList(Symbol), | 38 | symtab: std.ArrayList(Symbol), |
| | 39 | globals: struct { |
| | 40 | strong_def: std.array_hash_map.Auto(String(.strtab), Symbol.Global), |
| | 41 | weak_def: std.array_hash_map.Auto(String(.strtab), Symbol.Global), |
| | 42 | strong_undef: std.array_hash_map.Auto(String(.strtab), Symbol.Global), |
| | 43 | weak_undef: std.array_hash_map.Auto(String(.strtab), Symbol.Global), |
| | 44 | }, |
| | 45 | /// Key is a node which is a valid `Symbol.node` value, value is the name of the first global symbol |
| | 46 | /// in that node. That symbol is the head of a linked list: see `Symbol.Global.next_in_node`. |
| | 47 | /// |
| | 48 | /// Value is never `.empty`. |
| | 49 | /// |
| | 50 | /// We use a separate hash map for this data rather than storing it in `navs` etc to save memory, |
| | 51 | /// because the vast majority of nodes which can export global symbols actually will not. |
| | 52 | node_global_symbols: std.array_hash_map.Auto(MappedFile.Node.Index, String(.strtab)), |
| 30 | shstrtab: StringTable, | 53 | shstrtab: StringTable, |
| 31 | strtab: StringTable, | 54 | strtab: StringTable, |
| 32 | dynsym: std.AutoArrayHashMapUnmanaged(Symbol.Index, void), | | |
| 33 | dynstr: StringTable, | 55 | dynstr: StringTable, |
| 34 | got: struct { | 56 | got: struct { |
| 35 | len: u32, | 57 | len: u32, |
| 36 | tlsld: GotIndex, | 58 | tlsld: GotIndex, |
| 37 | plt: std.AutoArrayHashMapUnmanaged(Symbol.Index, void), | 59 | plt: std.AutoArrayHashMapUnmanaged(Symbol.Id, void), |
| 38 | }, | 60 | }, |
| 39 | needed: std.AutoArrayHashMapUnmanaged(u32, void), | 61 | first_plt_reloc: Reloc.Index, |
| | 62 | first_dynamic_reloc: Reloc.Index, |
| | 63 | needed: std.AutoArrayHashMapUnmanaged(String(.dynstr), void), |
| 40 | inputs: std.ArrayList(struct { | 64 | inputs: std.ArrayList(struct { |
| 41 | path: std.Build.Cache.Path, | 65 | path: std.Build.Cache.Path, |
| 42 | member: ?[]const u8, | 66 | member: ?[]const u8, |
| 43 | si: Symbol.Index, | 67 | file_symbol: Symbol.LocalIndex, |
| 44 | }), | | |
| 45 | input_sections: std.ArrayList(struct { | | |
| 46 | ii: Node.InputIndex, | | |
| 47 | file_location: MappedFile.Node.FileLocation, | | |
| 48 | si: Symbol.Index, | | |
| 49 | }), | 68 | }), |
| | 69 | input_sections: std.ArrayList(InputSection), |
| 50 | input_section_pending_index: u32, | 70 | input_section_pending_index: u32, |
| 51 | globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index), | 71 | navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, struct { |
| 52 | navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index), | 72 | /// The start index of the contiguous sequence of relocations in this NAV. |
| 53 | uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), | 73 | first_reloc: Reloc.Index, |
| | 74 | lsi: Symbol.LocalIndex, |
| | 75 | }), |
| | 76 | uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, struct { |
| | 77 | /// The start index of the contiguous sequence of relocations in this UAV. |
| | 78 | first_reloc: Reloc.Index, |
| | 79 | lsi: Symbol.LocalIndex, |
| | 80 | }), |
| 54 | lazy: std.EnumArray(link.File.LazySymbol.Kind, struct { | 81 | lazy: std.EnumArray(link.File.LazySymbol.Kind, struct { |
| 55 | map: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), | 82 | map: std.AutoArrayHashMapUnmanaged(InternPool.Index, struct { |
| | 83 | /// The start index of the contiguous sequence of relocations in this lazy code/data. |
| | 84 | first_reloc: Reloc.Index, |
| | 85 | lsi: Symbol.LocalIndex, |
| | 86 | }), |
| 56 | pending_index: u32, | 87 | pending_index: u32, |
| 57 | }), | 88 | }), |
| 58 | pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct { | 89 | pending_uavs: std.ArrayList(Node.UavMapIndex), |
| 59 | alignment: InternPool.Alignment, | | |
| 60 | src_loc: Zcu.LazySrcLoc, | | |
| 61 | }), | | |
| 62 | relocs: std.ArrayList(Reloc), | 90 | relocs: std.ArrayList(Reloc), |
| | 91 | |
| | 92 | /// Key is the name of a global symbol which has been moved to a new symtab index. Any relocation |
| | 93 | /// entries which target that symbol must be updated to reference the correct symbol index. |
| | 94 | changed_symtab_index: std.array_hash_map.Auto(String(.strtab), void), |
| | 95 | |
| 63 | const_prog_node: std.Progress.Node, | 96 | const_prog_node: std.Progress.Node, |
| 64 | synth_prog_node: std.Progress.Node, | 97 | synth_prog_node: std.Progress.Node, |
| 65 | input_prog_node: std.Progress.Node, | 98 | input_prog_node: std.Progress.Node, |
| 66 | | 99 | |
| 67 | pub const Node = union(enum) { | 100 | const Node = union(enum) { |
| | 101 | /// Cannot contain relocations. |
| 68 | file, | 102 | file, |
| | 103 | /// Cannot contain relocations. |
| 69 | ehdr, | 104 | ehdr, |
| | 105 | /// Cannot contain relocations. |
| 70 | shdr, | 106 | shdr, |
| | 107 | /// Cannot contain relocations. |
| 71 | segment: u32, | 108 | segment: u32, |
| 72 | section: Symbol.Index, | 109 | /// The section '.plt' may contain relocations via `elf.first_plt_reloc`. |
| 73 | input_section: InputSectionIndex, | 110 | /// |
| | 111 | /// The section '.dynamic' may contain relocations via `elf.first_dynamic_reloc`. |
| | 112 | /// |
| | 113 | /// Otherwise, cannot contain relocations. |
| | 114 | section: Section.Index, |
| | 115 | /// May contain relocations through the `first_reloc` field in `elf.input_sections`. |
| | 116 | input_section: InputSection.Index, |
| | 117 | /// May contain relocations through the `first_reloc` field in `elf.navs`. |
| 74 | nav: NavMapIndex, | 118 | nav: NavMapIndex, |
| | 119 | /// May contain relocations through the `first_reloc` field in `elf.uavs`. |
| 75 | uav: UavMapIndex, | 120 | uav: UavMapIndex, |
| | 121 | /// May contain relocations through the `first_reloc` field in `elf.lazy.map`. |
| 76 | lazy_code: LazyMapRef.Index(.code), | 122 | lazy_code: LazyMapRef.Index(.code), |
| | 123 | /// May contain relocations through the `first_reloc` field in `elf.lazy.map`. |
| 77 | lazy_const_data: LazyMapRef.Index(.const_data), | 124 | lazy_const_data: LazyMapRef.Index(.const_data), |
| 78 | | 125 | |
| 79 | pub const InputIndex = enum(u32) { | 126 | pub const InputIndex = enum(u32) { |
| ... | @@ -87,32 +134,20 @@ pub const Node = union(enum) { | ... | @@ -87,32 +134,20 @@ pub const Node = union(enum) { |
| 87 | return elf.inputs.items[@intFromEnum(ii)].member; | 134 | return elf.inputs.items[@intFromEnum(ii)].member; |
| 88 | } | 135 | } |
| 89 | | 136 | |
| 90 | pub fn symbol(ii: InputIndex, elf: *const Elf) Symbol.Index { | 137 | pub fn fileSymbol(ii: InputIndex, elf: *const Elf) Symbol.LocalIndex { |
| 91 | return elf.inputs.items[@intFromEnum(ii)].si; | 138 | return elf.inputs.items[@intFromEnum(ii)].file_symbol; |
| 92 | } | | |
| 93 | | | |
| 94 | pub fn endSymbol(ii: InputIndex, elf: *const Elf) Symbol.Index { | | |
| 95 | const next_ii = @intFromEnum(ii) + 1; | | |
| 96 | return if (next_ii < elf.inputs.items.len) | | |
| 97 | @as(InputIndex, @enumFromInt(next_ii)).symbol(elf) | | |
| 98 | else | | |
| 99 | @enumFromInt(elf.symtab.items.len); | | |
| 100 | } | | |
| 101 | }; | | |
| 102 | | | |
| 103 | pub const InputSectionIndex = enum(u32) { | | |
| 104 | _, | | |
| 105 | | | |
| 106 | pub fn input(isi: InputSectionIndex, elf: *const Elf) InputIndex { | | |
| 107 | return elf.input_sections.items[@intFromEnum(isi)].ii; | | |
| 108 | } | 139 | } |
| 109 | | 140 | |
| 110 | pub fn fileLocation(isi: InputSectionIndex, elf: *const Elf) MappedFile.Node.FileLocation { | 141 | pub fn localSymbolRange(ii: InputIndex, elf: *Elf) [2]Symbol.LocalIndex { |
| 111 | return elf.input_sections.items[@intFromEnum(isi)].file_location; | 142 | if (@intFromEnum(ii) + 1 < elf.inputs.items.len) { |
| 112 | } | 143 | const next_ii: InputIndex = @enumFromInt(@intFromEnum(ii) + 1); |
| 113 | | 144 | return .{ ii.fileSymbol(elf), next_ii.fileSymbol(elf) }; |
| 114 | pub fn symbol(isi: InputSectionIndex, elf: *const Elf) Symbol.Index { | 145 | } else { |
| 115 | return elf.input_sections.items[@intFromEnum(isi)].si; | 146 | const local_symbols_len = switch (elf.shdrPtr(.symtab)) { |
| | 147 | inline else => |shdr| elf.targetLoad(&shdr.info), |
| | 148 | }; |
| | 149 | return .{ ii.fileSymbol(elf), @enumFromInt(local_symbols_len) }; |
| | 150 | } |
| 116 | } | 151 | } |
| 117 | }; | 152 | }; |
| 118 | | 153 | |
| ... | @@ -123,8 +158,12 @@ pub const Node = union(enum) { | ... | @@ -123,8 +158,12 @@ pub const Node = union(enum) { |
| 123 | return elf.navs.keys()[@intFromEnum(nmi)]; | 158 | return elf.navs.keys()[@intFromEnum(nmi)]; |
| 124 | } | 159 | } |
| 125 | | 160 | |
| 126 | pub fn symbol(nmi: NavMapIndex, elf: *const Elf) Symbol.Index { | 161 | pub fn symbol(nmi: NavMapIndex, elf: *const Elf) Symbol.LocalIndex { |
| 127 | return elf.navs.values()[@intFromEnum(nmi)]; | 162 | return elf.navs.values()[@intFromEnum(nmi)].lsi; |
| | 163 | } |
| | 164 | |
| | 165 | fn firstReloc(nmi: NavMapIndex, elf: *const Elf) Reloc.Index { |
| | 166 | return elf.navs.values()[@intFromEnum(nmi)].first_reloc; |
| 128 | } | 167 | } |
| 129 | }; | 168 | }; |
| 130 | | 169 | |
| ... | @@ -135,8 +174,12 @@ pub const Node = union(enum) { | ... | @@ -135,8 +174,12 @@ pub const Node = union(enum) { |
| 135 | return elf.uavs.keys()[@intFromEnum(umi)]; | 174 | return elf.uavs.keys()[@intFromEnum(umi)]; |
| 136 | } | 175 | } |
| 137 | | 176 | |
| 138 | pub fn symbol(umi: UavMapIndex, elf: *const Elf) Symbol.Index { | 177 | pub fn symbol(umi: UavMapIndex, elf: *const Elf) Symbol.LocalIndex { |
| 139 | return elf.uavs.values()[@intFromEnum(umi)]; | 178 | return elf.uavs.values()[@intFromEnum(umi)].lsi; |
| | 179 | } |
| | 180 | |
| | 181 | fn firstReloc(umi: UavMapIndex, elf: *const Elf) Reloc.Index { |
| | 182 | return elf.uavs.values()[@intFromEnum(umi)].first_reloc; |
| 140 | } | 183 | } |
| 141 | }; | 184 | }; |
| 142 | | 185 | |
| ... | @@ -156,9 +199,13 @@ pub const Node = union(enum) { | ... | @@ -156,9 +199,13 @@ pub const Node = union(enum) { |
| 156 | return lmi.ref().lazySymbol(elf); | 199 | return lmi.ref().lazySymbol(elf); |
| 157 | } | 200 | } |
| 158 | | 201 | |
| 159 | pub fn symbol(lmi: @This(), elf: *const Elf) Symbol.Index { | 202 | pub fn symbol(lmi: @This(), elf: *const Elf) Symbol.LocalIndex { |
| 160 | return lmi.ref().symbol(elf); | 203 | return lmi.ref().symbol(elf); |
| 161 | } | 204 | } |
| | 205 | |
| | 206 | fn firstReloc(lmi: @This(), elf: *const Elf) Reloc.Index { |
| | 207 | return lmi.ref().firstReloc(elf); |
| | 208 | } |
| 162 | }; | 209 | }; |
| 163 | } | 210 | } |
| 164 | | 211 | |
| ... | @@ -166,8 +213,12 @@ pub const Node = union(enum) { | ... | @@ -166,8 +213,12 @@ pub const Node = union(enum) { |
| 166 | return .{ .kind = lmr.kind, .ty = elf.lazy.getPtrConst(lmr.kind).map.keys()[lmr.index] }; | 213 | return .{ .kind = lmr.kind, .ty = elf.lazy.getPtrConst(lmr.kind).map.keys()[lmr.index] }; |
| 167 | } | 214 | } |
| 168 | | 215 | |
| 169 | pub fn symbol(lmr: LazyMapRef, elf: *const Elf) Symbol.Index { | 216 | pub fn symbol(lmr: LazyMapRef, elf: *const Elf) Symbol.LocalIndex { |
| 170 | return elf.lazy.getPtrConst(lmr.kind).map.values()[lmr.index]; | 217 | return elf.lazy.getPtrConst(lmr.kind).map.values()[lmr.index].lsi; |
| | 218 | } |
| | 219 | |
| | 220 | fn firstReloc(lmr: LazyMapRef, elf: *const Elf) Reloc.Index { |
| | 221 | return elf.lazy.getPtrConst(lmr.kind).map.values()[lmr.index].first_reloc; |
| 171 | } | 222 | } |
| 172 | }; | 223 | }; |
| 173 | | 224 | |
| ... | @@ -180,17 +231,66 @@ pub const Node = union(enum) { | ... | @@ -180,17 +231,66 @@ pub const Node = union(enum) { |
| 180 | comptime text: MappedFile.Node.Index = @enumFromInt(5), | 231 | comptime text: MappedFile.Node.Index = @enumFromInt(5), |
| 181 | comptime data: MappedFile.Node.Index = @enumFromInt(6), | 232 | comptime data: MappedFile.Node.Index = @enumFromInt(6), |
| 182 | comptime data_rel_ro: MappedFile.Node.Index = @enumFromInt(7), | 233 | comptime data_rel_ro: MappedFile.Node.Index = @enumFromInt(7), |
| | 234 | |
| 183 | tls: MappedFile.Node.Index, | 235 | tls: MappedFile.Node.Index, |
| 184 | }; | 236 | }; |
| 185 | | 237 | |
| 186 | comptime { | 238 | comptime { |
| 187 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Node) == 8); | 239 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Node) == 8); |
| 188 | } | 240 | } |
| | 241 | |
| | 242 | /// In this linker implementation, `link.File.AtomId` is a type-erased `MappedFile.Node.Index`. |
| | 243 | fn toAtom(ni: MappedFile.Node.Index) link.File.AtomId { |
| | 244 | return @enumFromInt(@intFromEnum(ni)); |
| | 245 | } |
| | 246 | /// In this linker implementation, `link.File.AtomId` is a type-erased `MappedFile.Node.Index`. |
| | 247 | fn fromAtom(atom: link.File.AtomId) MappedFile.Node.Index { |
| | 248 | return @enumFromInt(@intFromEnum(atom)); |
| | 249 | } |
| 189 | }; | 250 | }; |
| 190 | | 251 | |
| 191 | pub const Section = struct { | 252 | const InputSection = struct { |
| 192 | si: Symbol.Index, | 253 | input: Node.InputIndex, |
| 193 | rela_si: Symbol.Index, | 254 | file_location: MappedFile.Node.FileLocation, |
| | 255 | vaddr: u64, |
| | 256 | /// The node corresponding to this input section. |
| | 257 | node: MappedFile.Node.Index, |
| | 258 | /// The start index of the contiguous sequence of relocations in this input section. |
| | 259 | first_reloc: Reloc.Index, |
| | 260 | |
| | 261 | const Index = enum(u32) { |
| | 262 | _, |
| | 263 | |
| | 264 | fn ptr(isi: InputSection.Index, elf: *Elf) *InputSection { |
| | 265 | return &elf.input_sections.items[@intFromEnum(isi)]; |
| | 266 | } |
| | 267 | |
| | 268 | fn ptrConst(isi: InputSection.Index, elf: *const Elf) *const InputSection { |
| | 269 | return &elf.input_sections.items[@intFromEnum(isi)]; |
| | 270 | } |
| | 271 | |
| | 272 | fn input(isi: InputSection.Index, elf: *const Elf) Node.InputIndex { |
| | 273 | return isi.ptrConst(elf).input; |
| | 274 | } |
| | 275 | |
| | 276 | fn fileLocation(isi: InputSection.Index, elf: *const Elf) MappedFile.Node.FileLocation { |
| | 277 | return isi.ptrConst(elf).file_location; |
| | 278 | } |
| | 279 | |
| | 280 | fn node(isi: InputSection.Index, elf: *const Elf) MappedFile.Node.Index { |
| | 281 | return isi.ptrConst(elf).node; |
| | 282 | } |
| | 283 | }; |
| | 284 | }; |
| | 285 | |
| | 286 | const Section = struct { |
| | 287 | /// The node corresponding to this section. |
| | 288 | ni: MappedFile.Node.Index, |
| | 289 | /// A symbol which is exactly at the start of this section. |
| | 290 | /// |
| | 291 | /// If the section does not have flag `std.elf.SHF.ALLOC`, this is `.null`. |
| | 292 | lsi: Symbol.LocalIndex, |
| | 293 | rela_shndx: Section.Index, |
| 194 | rela_free: RelIndex, | 294 | rela_free: RelIndex, |
| 195 | | 295 | |
| 196 | pub const RelIndex = enum(u32) { | 296 | pub const RelIndex = enum(u32) { |
| ... | @@ -207,394 +307,1165 @@ pub const Section = struct { | ... | @@ -207,394 +307,1165 @@ pub const Section = struct { |
| 207 | }; | 307 | }; |
| 208 | } | 308 | } |
| 209 | }; | 309 | }; |
| 210 | }; | | |
| 211 | | 310 | |
| 212 | pub const Symbol = struct { | 311 | pub const Index = enum(Tag) { |
| 213 | ni: MappedFile.Node.Index, | 312 | UNDEF = std.elf.SHN_UNDEF, |
| 214 | /// Relocations contained within this symbol | 313 | LIVEPATCH = reserve(std.elf.SHN_LIVEPATCH), |
| 215 | loc_relocs: Reloc.Index, | 314 | ABS = reserve(std.elf.SHN_ABS), |
| 216 | /// Relocations targeting this symbol | 315 | COMMON = reserve(std.elf.SHN_COMMON), |
| 217 | target_relocs: Reloc.Index, | | |
| 218 | unused: u32, | | |
| 219 | | 316 | |
| 220 | pub const Index = enum(u32) { | 317 | symtab = 1, |
| 221 | null, | | |
| 222 | symtab, | | |
| 223 | shstrtab, | 318 | shstrtab, |
| 224 | strtab, | 319 | strtab, |
| 225 | rodata, | 320 | rodata, |
| 226 | text, | 321 | text, |
| 227 | data, | 322 | data, |
| 228 | data_rel_ro, | 323 | data_rel_ro, |
| 229 | got, | 324 | |
| 230 | got_plt, | | |
| 231 | plt, | | |
| 232 | plt_sec, | | |
| 233 | _, | 325 | _, |
| 234 | | 326 | |
| 235 | pub fn get(si: Symbol.Index, elf: *Elf) *Symbol { | 327 | pub const Tag = u32; |
| 236 | return &elf.symtab.items[@intFromEnum(si)]; | 328 | |
| | 329 | pub const LORESERVE: Index = .fromSection(std.elf.SHN_LORESERVE); |
| | 330 | pub const HIRESERVE: Index = .fromSection(std.elf.SHN_HIRESERVE); |
| | 331 | comptime { |
| | 332 | assert(@intFromEnum(HIRESERVE) == std.math.maxInt(Tag)); |
| 237 | } | 333 | } |
| 238 | | 334 | |
| 239 | pub fn node(si: Symbol.Index, elf: *Elf) MappedFile.Node.Index { | 335 | fn reserve(sec: std.elf.Section) Tag { |
| 240 | const ni = si.get(elf).ni; | 336 | assert(sec >= std.elf.SHN_LORESERVE and sec <= std.elf.SHN_HIRESERVE); |
| 241 | assert(ni != .none); | 337 | return @as(Tag, std.math.maxInt(Tag) - std.elf.SHN_HIRESERVE) + sec; |
| 242 | return ni; | | |
| 243 | } | 338 | } |
| 244 | | 339 | |
| 245 | pub fn next(si: Symbol.Index) Symbol.Index { | 340 | pub fn fromSection(sec: std.elf.Section) Index { |
| 246 | return @enumFromInt(@intFromEnum(si) + 1); | 341 | return switch (sec) { |
| | 342 | std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => @enumFromInt(sec), |
| | 343 | std.elf.SHN_LORESERVE...std.elf.SHN_HIRESERVE => @enumFromInt(reserve(sec)), |
| | 344 | }; |
| | 345 | } |
| | 346 | pub fn toSection(s: Index) ?std.elf.Section { |
| | 347 | return switch (@intFromEnum(s)) { |
| | 348 | std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => |sec| @intCast(sec), |
| | 349 | std.elf.SHN_LORESERVE...reserve(std.elf.SHN_LORESERVE) - 1 => null, |
| | 350 | reserve(std.elf.SHN_LORESERVE)...reserve(std.elf.SHN_HIRESERVE) => |sec| @intCast( |
| | 351 | sec - reserve(std.elf.SHN_LORESERVE) + std.elf.SHN_LORESERVE, |
| | 352 | ), |
| | 353 | }; |
| 247 | } | 354 | } |
| 248 | | 355 | |
| 249 | pub const Shndx = enum(Tag) { | 356 | fn get(s: Index, elf: *Elf) *Section { |
| 250 | UNDEF = std.elf.SHN_UNDEF, | 357 | return &elf.shdrs.items[@intFromEnum(s)]; |
| 251 | LIVEPATCH = reserve(std.elf.SHN_LIVEPATCH), | 358 | } |
| 252 | ABS = reserve(std.elf.SHN_ABS), | | |
| 253 | COMMON = reserve(std.elf.SHN_COMMON), | | |
| 254 | _, | | |
| 255 | | 359 | |
| 256 | pub const Tag = u32; | 360 | fn name(s: Index, elf: *Elf) [:0]const u8 { |
| | 361 | const str: String(.shstrtab) = switch (elf.shdrPtr(s)) { |
| | 362 | inline else => |shdr| @enumFromInt(elf.targetLoad(&shdr.name)), |
| | 363 | }; |
| | 364 | return str.slice(elf); |
| | 365 | } |
| 257 | | 366 | |
| 258 | pub const LORESERVE: Shndx = .fromSection(std.elf.SHN_LORESERVE); | 367 | fn vaddr(s: Index, elf: *Elf) u64 { |
| 259 | pub const HIRESERVE: Shndx = .fromSection(std.elf.SHN_HIRESERVE); | 368 | return switch (s.get(elf).lsi) { |
| 260 | comptime { | 369 | .null => 0, |
| 261 | assert(@intFromEnum(HIRESERVE) == std.math.maxInt(Tag)); | 370 | else => |lsi| Symbol.Id.local(lsi).value(elf), |
| 262 | } | 371 | }; |
| | 372 | } |
| 263 | | 373 | |
| 264 | fn reserve(sec: std.elf.Section) Tag { | 374 | fn rename(shndx: Index, elf: *Elf, new_name: []const u8) !void { |
| 265 | assert(sec >= std.elf.SHN_LORESERVE and sec <= std.elf.SHN_HIRESERVE); | 375 | const shstrtab_entry = try elf.string(.shstrtab, new_name); |
| 266 | return @as(Tag, std.math.maxInt(Tag) - std.elf.SHN_HIRESERVE) + sec; | 376 | switch (elf.shdrPtr(shndx)) { |
| | 377 | inline else => |shdr| elf.targetStore(&shdr.name, @intFromEnum(shstrtab_entry)), |
| 267 | } | 378 | } |
| | 379 | } |
| | 380 | }; |
| | 381 | }; |
| | 382 | |
| | 383 | fn ensureUnusedSymbolCapacity(elf: *Elf, len: u32, kind: enum { all_local, maybe_global }) !void { |
| | 384 | const gpa = elf.base.comp.gpa; |
| | 385 | |
| | 386 | try elf.symtab.ensureUnusedCapacity(gpa, len); |
| | 387 | |
| | 388 | // If adding locals, we may need to move one global out of the way for each local. If adding |
| | 389 | // globals, they could all get demoted to STB_LOCAL, which would mean we move those N globals |
| | 390 | // *and* we move up to N other globals out of their way. |
| | 391 | try elf.changed_symtab_index.ensureUnusedCapacity(gpa, switch (kind) { |
| | 392 | .all_local => len, |
| | 393 | .maybe_global => len * 2, |
| | 394 | }); |
| | 395 | |
| | 396 | { |
| | 397 | // Ensure the symtab section's node is big enough |
| | 398 | const need_node_size: u64 = switch (elf.shdrPtr(.symtab)) { |
| | 399 | inline else => |shdr, class| elf.targetLoad(&shdr.size) + len * @sizeOf(class.ElfN().Sym), |
| | 400 | }; |
| | 401 | _, const cur_node_size = Section.Index.symtab.get(elf).ni.location(&elf.mf).resolve(&elf.mf); |
| | 402 | if (cur_node_size < need_node_size) { |
| | 403 | const new_node_size = need_node_size +| need_node_size / MappedFile.growth_factor; |
| | 404 | try Section.Index.symtab.get(elf).ni.resize(&elf.mf, gpa, new_node_size); |
| | 405 | } |
| | 406 | } |
| | 407 | |
| | 408 | switch (kind) { |
| | 409 | .all_local => {}, |
| | 410 | .maybe_global => { |
| | 411 | try elf.globals.strong_def.ensureUnusedCapacity(gpa, len); |
| | 412 | try elf.globals.weak_def.ensureUnusedCapacity(gpa, len); |
| | 413 | try elf.globals.strong_undef.ensureUnusedCapacity(gpa, len); |
| | 414 | try elf.globals.weak_undef.ensureUnusedCapacity(gpa, len); |
| | 415 | |
| | 416 | try elf.node_global_symbols.ensureUnusedCapacity(gpa, len); |
| 268 | | 417 | |
| 269 | pub fn fromSection(sec: std.elf.Section) Shndx { | 418 | if (elf.shndx.dynsym != .UNDEF) { |
| 270 | return switch (sec) { | 419 | // Ensure the `.dynsym` section's node is big enough |
| 271 | std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => @enumFromInt(sec), | 420 | const dynsym_need_size: u64 = switch (elf.shdrPtr(elf.shndx.dynsym)) { |
| 272 | std.elf.SHN_LORESERVE...std.elf.SHN_HIRESERVE => @enumFromInt(reserve(sec)), | 421 | inline else => |shdr, class| elf.targetLoad(&shdr.size) + len * @sizeOf(class.ElfN().Sym), |
| 273 | }; | 422 | }; |
| | 423 | _, const dynsym_cur_size = elf.shndx.dynsym.get(elf).ni.location(&elf.mf).resolve(&elf.mf); |
| | 424 | if (dynsym_cur_size < dynsym_need_size) { |
| | 425 | const new_size = dynsym_need_size +| dynsym_need_size / MappedFile.growth_factor; |
| | 426 | try elf.shndx.dynsym.get(elf).ni.resize(&elf.mf, gpa, new_size); |
| | 427 | } |
| | 428 | |
| | 429 | try elf.got.plt.ensureUnusedCapacity(gpa, len); |
| | 430 | const need_plt_capacity = elf.got.plt.count() + len; |
| | 431 | |
| | 432 | switch (elf.ehdrField(.machine)) { |
| | 433 | else => |machine| @panic(@tagName(machine)), |
| | 434 | .X86_64 => { |
| | 435 | // Ensure the `.plt` section's node is big enough |
| | 436 | const plt_need_size: usize = 16 * (1 + need_plt_capacity); |
| | 437 | _, const plt_cur_size = elf.shndx.plt.get(elf).ni.location(&elf.mf).resolve(&elf.mf); |
| | 438 | if (plt_cur_size < plt_need_size) { |
| | 439 | const new_size = plt_need_size +| plt_need_size / MappedFile.growth_factor; |
| | 440 | try elf.shndx.plt.get(elf).ni.resize(&elf.mf, gpa, new_size); |
| | 441 | } |
| | 442 | |
| | 443 | // Ensure the `.got.plt` section's node is big enough |
| | 444 | const got_plt_need_size: usize = switch (elf.identClass()) { |
| | 445 | .NONE, _ => unreachable, |
| | 446 | inline else => |class| @sizeOf(class.ElfN().Addr) * (3 + need_plt_capacity), |
| | 447 | }; |
| | 448 | _, const got_plt_cur_size = elf.shndx.got_plt.get(elf).ni.location(&elf.mf).resolve(&elf.mf); |
| | 449 | if (got_plt_cur_size < got_plt_need_size) { |
| | 450 | const new_size = got_plt_need_size +| got_plt_need_size / MappedFile.growth_factor; |
| | 451 | try elf.shndx.got_plt.get(elf).ni.resize(&elf.mf, gpa, new_size); |
| | 452 | } |
| | 453 | |
| | 454 | // Ensure the `.plt.sec` section's node is big enough |
| | 455 | const plt_sec_need_size: usize = 16 * need_plt_capacity; |
| | 456 | _, const plt_sec_cur_size = elf.shndx.plt_sec.get(elf).ni.location(&elf.mf).resolve(&elf.mf); |
| | 457 | if (plt_sec_cur_size < plt_sec_need_size) { |
| | 458 | const new_size = plt_sec_need_size +| plt_sec_need_size / MappedFile.growth_factor; |
| | 459 | try elf.shndx.plt_sec.get(elf).ni.resize(&elf.mf, gpa, new_size); |
| | 460 | } |
| | 461 | |
| | 462 | // Ensure the `.rela.plt` section's node is big enough |
| | 463 | const rela_plt_shndx = elf.shndx.got_plt.get(elf).rela_shndx; |
| | 464 | const rela_plt_need_size: usize = switch (elf.shdrPtr(rela_plt_shndx)) { |
| | 465 | inline else => |shdr| @intCast(elf.targetLoad(&shdr.entsize) * need_plt_capacity), |
| | 466 | }; |
| | 467 | _, const rela_plt_cur_size = rela_plt_shndx.get(elf).ni.location(&elf.mf).resolve(&elf.mf); |
| | 468 | if (rela_plt_cur_size < rela_plt_need_size) { |
| | 469 | const new_size = rela_plt_need_size +| rela_plt_need_size / MappedFile.growth_factor; |
| | 470 | try rela_plt_shndx.get(elf).ni.resize(&elf.mf, gpa, new_size); |
| | 471 | } else { |
| | 472 | // Still mark `.rela.plt` as resized so that the DT_PLTRELSZ entry can |
| | 473 | // be updated if we do indeed add a PLT entry. |
| | 474 | try rela_plt_shndx.get(elf).ni.resized(gpa, &elf.mf); |
| | 475 | } |
| | 476 | }, |
| | 477 | } |
| 274 | } | 478 | } |
| 275 | pub fn toSection(s: Shndx) ?std.elf.Section { | 479 | }, |
| 276 | return switch (@intFromEnum(s)) { | 480 | } |
| 277 | std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => |sec| @intCast(sec), | 481 | } |
| 278 | std.elf.SHN_LORESERVE...reserve(std.elf.SHN_LORESERVE) - 1 => null, | 482 | |
| 279 | reserve(std.elf.SHN_LORESERVE)...reserve(std.elf.SHN_HIRESERVE) => |sec| @intCast( | 483 | const AddLocalSymbolOptions = struct { |
| 280 | sec - reserve(std.elf.SHN_LORESERVE) + std.elf.SHN_LORESERVE, | 484 | node: MappedFile.Node.Index, |
| 281 | ), | 485 | name: String(.strtab), |
| 282 | }; | 486 | value: u64, |
| | 487 | size: u64, |
| | 488 | type: std.elf.STT, |
| | 489 | shndx: Section.Index, |
| | 490 | }; |
| | 491 | fn addLocalSymbolAssumeCapacity(elf: *Elf, opts: AddLocalSymbolOptions) Symbol.LocalIndex { |
| | 492 | switch (elf.shdrPtr(.symtab)) { |
| | 493 | inline else => |shdr, class| { |
| | 494 | const ent_size = @sizeOf(class.ElfN().Sym); |
| | 495 | |
| | 496 | // `shdr.info` stores the index of the first global symbol. We will replace it with our |
| | 497 | // new local symbol, and move the global symbol to a new index at the end of the symtab. |
| | 498 | const target_index: Symbol.Index = @enumFromInt(elf.targetLoad(&shdr.info)); |
| | 499 | |
| | 500 | const old_size = elf.targetLoad(&shdr.size); |
| | 501 | const new_size = old_size + ent_size; |
| | 502 | |
| | 503 | assert(elf.symtab.items.len == @divExact(old_size, ent_size)); |
| | 504 | |
| | 505 | elf.targetStore(&shdr.info, @intFromEnum(target_index) + 1); |
| | 506 | elf.targetStore(&shdr.size, new_size); |
| | 507 | |
| | 508 | const new_index: Symbol.Index = @enumFromInt(elf.symtab.items.len); |
| | 509 | elf.symtab.appendAssumeCapacity(undefined); |
| | 510 | |
| | 511 | const target_sym = @field(elf.symPtr(target_index), @tagName(class)); |
| | 512 | |
| | 513 | if (target_index != new_index) { |
| | 514 | // Move the global at `target_index` to `new_index`. First the symtab entry... |
| | 515 | const new_sym = @field(elf.symPtr(new_index), @tagName(class)); |
| | 516 | new_sym.* = target_sym.*; |
| | 517 | // ...then the `elf.symtab` metadata... |
| | 518 | new_index.ptr(elf).* = target_index.ptr(elf).*; |
| | 519 | // ...then update the `elf.globals` tracking. |
| | 520 | const global_name: String(.strtab) = @enumFromInt(elf.targetLoad(&new_sym.name)); |
| | 521 | elf.globalByName(global_name).?.symtab_index = new_index; |
| | 522 | |
| | 523 | if (target_index.ptr(elf).first_target_reloc != .none) { |
| | 524 | // This symbol's index is changing, so queue an update of relocs targeting it. |
| | 525 | elf.changed_symtab_index.putAssumeCapacity(global_name, {}); |
| | 526 | } |
| 283 | } | 527 | } |
| 284 | | 528 | |
| 285 | pub fn get(s: Shndx, elf: *Elf) *Section { | 529 | target_index.ptr(elf).* = .{ |
| 286 | return &elf.shdrs.items[@intFromEnum(s)]; | 530 | .node = opts.node, |
| | 531 | .first_target_reloc = .none, |
| | 532 | }; |
| | 533 | |
| | 534 | target_sym.* = .{ |
| | 535 | .name = @intFromEnum(opts.name), |
| | 536 | .value = @intCast(opts.value), |
| | 537 | .size = @intCast(opts.size), |
| | 538 | .info = .{ .type = opts.type, .bind = .LOCAL }, |
| | 539 | .other = .{ .visibility = .DEFAULT }, |
| | 540 | .shndx = opts.shndx.toSection().?, |
| | 541 | }; |
| | 542 | if (elf.targetEndian() != native_endian) { |
| | 543 | std.mem.byteSwapAllFields(class.ElfN().Sym, target_sym); |
| 287 | } | 544 | } |
| 288 | }; | | |
| 289 | pub fn shndx(si: Symbol.Index, elf: *Elf) Shndx { | | |
| 290 | return .fromSection(switch (elf.symPtr(si)) { | | |
| 291 | inline else => |sym| elf.targetLoad(&sym.shndx), | | |
| 292 | }); | | |
| 293 | } | | |
| 294 | | 545 | |
| 295 | pub const InitOptions = struct { | 546 | return @enumFromInt(@intFromEnum(target_index)); |
| 296 | name: []const u8 = "", | 547 | }, |
| 297 | lib_name: ?[]const u8 = null, | 548 | } |
| 298 | value: u64 = 0, | 549 | } |
| 299 | size: u64 = 0, | 550 | |
| 300 | type: std.elf.STT, | 551 | const AddGlobalSymbolOptions = struct { |
| 301 | bind: std.elf.STB = .LOCAL, | 552 | const Name = struct { |
| 302 | visibility: std.elf.STV = .DEFAULT, | 553 | strtab: String(.strtab), |
| 303 | shndx: Shndx = .UNDEF, | 554 | dynstr: String(.dynstr), |
| 304 | }; | 555 | fn string(elf: *Elf, slice: []const u8) !Name { |
| 305 | pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void { | 556 | return .{ |
| 306 | const comp = elf.base.comp; | 557 | .strtab = try elf.string(.strtab, slice), |
| 307 | const gpa = comp.gpa; | 558 | .dynstr = switch (elf.shndx.dynsym) { |
| 308 | const target_endian = elf.targetEndian(); | 559 | .UNDEF => .empty, |
| 309 | const name_strtab_entry = try elf.string(.strtab, opts.name); | 560 | else => try elf.string(.dynstr, slice), |
| 310 | switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) { | | |
| 311 | inline else => |shdr| { | | |
| 312 | const old_size = elf.targetLoad(&shdr.size); | | |
| 313 | const ent_size = elf.targetLoad(&shdr.entsize); | | |
| 314 | const new_size = ent_size * elf.symtab.items.len; | | |
| 315 | if (new_size > old_size) { | | |
| 316 | elf.targetStore(&shdr.size, @intCast(new_size)); | | |
| 317 | const symtab_ni = elf.si.symtab.node(elf); | | |
| 318 | _, const node_size = symtab_ni.location(&elf.mf).resolve(&elf.mf); | | |
| 319 | if (new_size > node_size) try symtab_ni.resize( | | |
| 320 | &elf.mf, | | |
| 321 | gpa, | | |
| 322 | new_size +| new_size / MappedFile.growth_factor, | | |
| 323 | ); | | |
| 324 | } | | |
| 325 | }, | 561 | }, |
| | 562 | }; |
| | 563 | } |
| | 564 | }; |
| | 565 | |
| | 566 | node: MappedFile.Node.Index, |
| | 567 | name: Name, |
| | 568 | lib_name: ?[]const u8 = null, |
| | 569 | value: u64, |
| | 570 | size: u64, |
| | 571 | type: std.elf.STT, |
| | 572 | bind: enum { strong, weak }, |
| | 573 | visibility: std.elf.STV, |
| | 574 | shndx: Section.Index, |
| | 575 | }; |
| | 576 | fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{MultipleDefinitions}!Symbol.Id { |
| | 577 | _ = opts.lib_name; // TODO |
| | 578 | |
| | 579 | if (elf.shndx.dynsym == .UNDEF) { |
| | 580 | assert(opts.name.dynstr == .empty); |
| | 581 | } else { |
| | 582 | assert(std.mem.eql(u8, opts.name.dynstr.slice(elf), opts.name.strtab.slice(elf))); |
| | 583 | } |
| | 584 | |
| | 585 | // We break from this `switch` only if this symbol name did not previously exist at all and so |
| | 586 | // we have added a new entry to one of the maps in `elf.globals`. In that case we actually need |
| | 587 | // a new symtab entry. |
| | 588 | const new_global_ptr: *Symbol.Global = if (opts.shndx != .UNDEF) switch (opts.bind) { |
| | 589 | .strong => new_global: { |
| | 590 | const gop = elf.globals.strong_def.getOrPutAssumeCapacity(opts.name.strtab); |
| | 591 | if (gop.found_existing) return error.MultipleDefinitions; |
| | 592 | const old_kv = elf.globals.weak_def.fetchSwapRemove(opts.name.strtab) orelse |
| | 593 | elf.globals.strong_undef.fetchSwapRemove(opts.name.strtab) orelse |
| | 594 | elf.globals.weak_undef.fetchSwapRemove(opts.name.strtab) orelse { |
| | 595 | // The symbol did not already exist, so we'll use the "new global" path. |
| | 596 | break :new_global gop.value_ptr; |
| | 597 | }; |
| | 598 | gop.value_ptr.* = old_kv.value; |
| | 599 | elf.setGlobalSymbolValue(opts.name.strtab, gop.value_ptr, .{ |
| | 600 | .node = opts.node, |
| | 601 | .value = opts.value, |
| | 602 | .size = opts.size, |
| | 603 | .type = opts.type, |
| | 604 | .shndx = opts.shndx, |
| | 605 | }); |
| | 606 | elf.mergeGlobalSymbolVisibility(gop.value_ptr, opts.visibility, .strong); |
| | 607 | return .global(opts.name.strtab); |
| | 608 | }, |
| | 609 | .weak => new_global: { |
| | 610 | if (elf.globals.strong_def.getPtr(opts.name.strtab)) |global| { |
| | 611 | // The existing definition holds, we just merge our visibility in. |
| | 612 | elf.mergeGlobalSymbolVisibility(global, opts.visibility, .strong); |
| | 613 | return .global(opts.name.strtab); |
| 326 | } | 614 | } |
| 327 | switch (elf.symPtr(si)) { | 615 | const gop = elf.globals.weak_def.getOrPutAssumeCapacity(opts.name.strtab); |
| 328 | inline else => |sym, class| { | 616 | if (gop.found_existing) { |
| | 617 | // The existing definition holds, we just merge our visibility in. |
| | 618 | elf.mergeGlobalSymbolVisibility(gop.value_ptr, opts.visibility, .weak); |
| | 619 | return .global(opts.name.strtab); |
| | 620 | } |
| | 621 | const old_kv = elf.globals.strong_undef.fetchSwapRemove(opts.name.strtab) orelse |
| | 622 | elf.globals.weak_undef.fetchSwapRemove(opts.name.strtab) orelse { |
| | 623 | // The symbol did not already exist, so we'll use the "new global" path. |
| | 624 | break :new_global gop.value_ptr; |
| | 625 | }; |
| | 626 | gop.value_ptr.* = old_kv.value; |
| | 627 | elf.setGlobalSymbolValue(opts.name.strtab, gop.value_ptr, .{ |
| | 628 | .node = opts.node, |
| | 629 | .value = opts.value, |
| | 630 | .size = opts.size, |
| | 631 | .type = opts.type, |
| | 632 | .shndx = opts.shndx, |
| | 633 | }); |
| | 634 | elf.mergeGlobalSymbolVisibility(gop.value_ptr, opts.visibility, .weak); |
| | 635 | return .global(opts.name.strtab); |
| | 636 | }, |
| | 637 | } else switch (opts.bind) { |
| | 638 | .strong => new_global: { |
| | 639 | if (elf.globals.strong_def.getPtr(opts.name.strtab)) |global| { |
| | 640 | // The existing definition holds, we just merge our visibility in. |
| | 641 | elf.mergeGlobalSymbolVisibility(global, opts.visibility, .strong); |
| | 642 | return .global(opts.name.strtab); |
| | 643 | } |
| | 644 | if (elf.globals.weak_def.getPtr(opts.name.strtab)) |global| { |
| | 645 | // The existing definition holds, we just merge our visibility in. |
| | 646 | elf.mergeGlobalSymbolVisibility(global, opts.visibility, .weak); |
| | 647 | return .global(opts.name.strtab); |
| | 648 | } |
| | 649 | const gop = elf.globals.strong_undef.getOrPutAssumeCapacity(opts.name.strtab); |
| | 650 | if (gop.found_existing) { |
| | 651 | // The existing symbol is okay, we just merge our visibility in. |
| | 652 | elf.mergeGlobalSymbolVisibility(gop.value_ptr, opts.visibility, .strong); |
| | 653 | return .global(opts.name.strtab); |
| | 654 | } |
| | 655 | const old_kv = elf.globals.weak_undef.fetchSwapRemove(opts.name.strtab) orelse { |
| | 656 | // The symbol did not already exist, so we'll use the "new global" path. |
| | 657 | break :new_global gop.value_ptr; |
| | 658 | }; |
| | 659 | gop.value_ptr.* = old_kv.value; |
| | 660 | elf.mergeGlobalSymbolVisibility(gop.value_ptr, opts.visibility, .strong); |
| | 661 | return .global(opts.name.strtab); |
| | 662 | }, |
| | 663 | .weak => new_global: { |
| | 664 | if (elf.globals.strong_def.getPtr(opts.name.strtab) orelse |
| | 665 | elf.globals.strong_undef.getPtr(opts.name.strtab)) |global| |
| | 666 | { |
| | 667 | // The existing symbol is okay, we just merge our visibility in. |
| | 668 | elf.mergeGlobalSymbolVisibility(global, opts.visibility, .strong); |
| | 669 | return .global(opts.name.strtab); |
| | 670 | } |
| | 671 | if (elf.globals.weak_def.getPtr(opts.name.strtab)) |global| { |
| | 672 | // The existing symbol is okay, we just merge our visibility in. |
| | 673 | elf.mergeGlobalSymbolVisibility(global, opts.visibility, .weak); |
| | 674 | return .global(opts.name.strtab); |
| | 675 | } |
| | 676 | const gop = elf.globals.weak_undef.getOrPutAssumeCapacity(opts.name.strtab); |
| | 677 | if (gop.found_existing) { |
| | 678 | // The existing symbol is okay, we just merge our visibility in. |
| | 679 | elf.mergeGlobalSymbolVisibility(gop.value_ptr, opts.visibility, .weak); |
| | 680 | return .global(opts.name.strtab); |
| | 681 | } |
| | 682 | break :new_global gop.value_ptr; |
| | 683 | }, |
| | 684 | }; |
| | 685 | |
| | 686 | const force_local_bind: bool = switch (opts.visibility) { |
| | 687 | .HIDDEN, .INTERNAL => elf.ehdrField(.type) != .REL, |
| | 688 | .PROTECTED, .DEFAULT => false, |
| | 689 | }; |
| | 690 | |
| | 691 | const bind: std.elf.STB = if (force_local_bind) b: { |
| | 692 | break :b .LOCAL; |
| | 693 | } else switch (opts.bind) { |
| | 694 | .strong => .GLOBAL, |
| | 695 | .weak => .WEAK, |
| | 696 | }; |
| | 697 | |
| | 698 | const sym_index: Symbol.Index = @enumFromInt(elf.symtab.items.len); |
| | 699 | elf.symtab.appendAssumeCapacity(.{ |
| | 700 | .node = opts.node, |
| | 701 | .first_target_reloc = .none, |
| | 702 | }); |
| | 703 | switch (elf.shdrPtr(.symtab)) { |
| | 704 | inline else => |shdr, class| { |
| | 705 | const Sym = class.ElfN().Sym; |
| | 706 | // Increase the symtab size... |
| | 707 | const old_size = elf.targetLoad(&shdr.size); |
| | 708 | assert(old_size == @intFromEnum(sym_index) * @sizeOf(Sym)); |
| | 709 | elf.targetStore(&shdr.size, old_size + @sizeOf(Sym)); |
| | 710 | // ...then populate the newly-valid symbol pointer |
| | 711 | const sym = @field(elf.symPtr(sym_index), @tagName(class)); |
| | 712 | sym.* = .{ |
| | 713 | .name = @intFromEnum(opts.name.strtab), |
| | 714 | .value = @intCast(opts.value), |
| | 715 | .size = @intCast(opts.size), |
| | 716 | .info = .{ .type = opts.type, .bind = bind }, |
| | 717 | .other = .{ .visibility = opts.visibility }, |
| | 718 | .shndx = opts.shndx.toSection().?, |
| | 719 | }; |
| | 720 | if (elf.targetEndian() != native_endian) { |
| | 721 | std.mem.byteSwapAllFields(Sym, sym); |
| | 722 | } |
| | 723 | }, |
| | 724 | } |
| | 725 | |
| | 726 | const old_head: String(.strtab) = old_head: { |
| | 727 | if (opts.node == .none) break :old_head .empty; |
| | 728 | const gop = elf.node_global_symbols.getOrPutAssumeCapacity(opts.node); |
| | 729 | const old_head: String(.strtab) = if (gop.found_existing) gop.value_ptr.* else .empty; |
| | 730 | gop.value_ptr.* = opts.name.strtab; |
| | 731 | break :old_head old_head; |
| | 732 | }; |
| | 733 | |
| | 734 | new_global_ptr.* = .{ |
| | 735 | .symtab_index = sym_index, |
| | 736 | .dynsym_index = dynsym_index: { |
| | 737 | if (elf.shndx.dynsym == .UNDEF) break :dynsym_index 0; |
| | 738 | if (force_local_bind) break :dynsym_index 0; |
| | 739 | switch (elf.shdrPtr(elf.shndx.dynsym)) { |
| | 740 | inline else => |shdr, class| { |
| 329 | const Sym = class.ElfN().Sym; | 741 | const Sym = class.ElfN().Sym; |
| | 742 | // Increase the dynamic symbol table size... |
| | 743 | const old_size = elf.targetLoad(&shdr.size); |
| | 744 | elf.targetStore(&shdr.size, old_size + @sizeOf(Sym)); |
| | 745 | const dynsym_index: u32 = @intCast(@divExact(old_size, @sizeOf(Sym))); |
| | 746 | // ...then populate the newly-valid symbol pointer |
| | 747 | const sym = @field(elf.dynsymPtr(dynsym_index), @tagName(class)); |
| 330 | sym.* = .{ | 748 | sym.* = .{ |
| 331 | .name = name_strtab_entry, | 749 | .name = @intFromEnum(opts.name.dynstr), |
| 332 | .value = @intCast(opts.value), | 750 | .value = @intCast(opts.value), |
| 333 | .size = @intCast(opts.size), | 751 | .size = @intCast(opts.size), |
| 334 | .info = .{ .type = opts.type, .bind = opts.bind }, | 752 | .info = .{ .type = opts.type, .bind = bind }, |
| 335 | .other = .{ .visibility = opts.visibility }, | 753 | .other = .{ .visibility = opts.visibility }, |
| 336 | .shndx = opts.shndx.toSection().?, | 754 | .shndx = opts.shndx.toSection().?, |
| 337 | }; | 755 | }; |
| 338 | if (target_endian != native_endian) std.mem.byteSwapAllFields(Sym, sym); | 756 | if (elf.targetEndian() != native_endian) { |
| | 757 | std.mem.byteSwapAllFields(Sym, sym); |
| | 758 | } |
| | 759 | break :dynsym_index dynsym_index; |
| 339 | }, | 760 | }, |
| 340 | } | 761 | } |
| 341 | switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) { | 762 | }, |
| 342 | inline else => |shdr| elf.targetStore(&shdr.info, @max( | 763 | .prev_in_node = .empty, |
| 343 | elf.targetLoad(&shdr.info), | 764 | .next_in_node = old_head, |
| 344 | @intFromEnum(si) + 1, | 765 | }; |
| 345 | )), | | |
| 346 | } | | |
| 347 | | 766 | |
| 348 | if (opts.bind == .LOCAL) return; | 767 | if (old_head != .empty) { |
| 349 | no_entry: { | 768 | const old_head_ptr = elf.globalByName(old_head).?; |
| 350 | if (std.mem.eql(u8, opts.name, entry: switch (elf.options.entry) { | 769 | assert(old_head_ptr.symtab_index.ptr(elf).node == opts.node); |
| 351 | .default => switch (comp.config.output_mode) { | 770 | assert(old_head_ptr.prev_in_node == .empty); |
| 352 | .Exe => continue :entry .enabled, | 771 | old_head_ptr.prev_in_node = opts.name.strtab; |
| 353 | .Lib, .Obj => continue :entry .disabled, | 772 | } |
| 354 | }, | 773 | |
| 355 | .disabled => break :no_entry, | 774 | if (force_local_bind) { |
| 356 | .enabled => "_start", | 775 | elf.moveDemotedGlobal(new_global_ptr); |
| 357 | .named => |named| named, | 776 | } |
| 358 | })) { | 777 | |
| 359 | elf.si.entry = si; | 778 | if (new_global_ptr.dynsym_index != 0 and |
| 360 | switch (elf.ehdrPtr()) { | 779 | opts.visibility == .DEFAULT and |
| 361 | inline else => |ehdr| elf.targetStore(&ehdr.entry, @intCast(opts.value)), | 780 | opts.shndx == .UNDEF and |
| 362 | } | 781 | opts.type == .FUNC) |
| 363 | } | 782 | { |
| | 783 | // We're adding an undefined global STT_FUNC symbol which could be resolved by another DSO. |
| | 784 | // We therefore might need a PLT entry, so let's add one now. TODO: it'd be good to remove |
| | 785 | // the PLT entry if we later discover a link inpu which resolves this reference. |
| | 786 | elf.addPltEntry(opts.name.strtab, new_global_ptr.dynsym_index); |
| | 787 | } |
| | 788 | |
| | 789 | return .global(opts.name.strtab); |
| | 790 | } |
| | 791 | fn setGlobalSymbolValue( |
| | 792 | elf: *Elf, |
| | 793 | global_name: String(.strtab), |
| | 794 | global_ptr: *Symbol.Global, |
| | 795 | new: struct { |
| | 796 | node: MappedFile.Node.Index, |
| | 797 | value: u64, |
| | 798 | size: u64, |
| | 799 | type: std.elf.STT, |
| | 800 | shndx: Section.Index, |
| | 801 | }, |
| | 802 | ) void { |
| | 803 | const old_node = global_ptr.symtab_index.ptr(elf).node; |
| | 804 | if (old_node != .none) { |
| | 805 | if (global_ptr.next_in_node != .empty) { |
| | 806 | const next = elf.globalByName(global_ptr.next_in_node).?; |
| | 807 | assert(next.prev_in_node == global_name); |
| | 808 | assert(next.symtab_index.ptr(elf).node == old_node); |
| | 809 | next.prev_in_node = global_ptr.prev_in_node; |
| | 810 | } |
| | 811 | if (global_ptr.prev_in_node != .empty) { |
| | 812 | const prev = elf.globalByName(global_ptr.prev_in_node).?; |
| | 813 | assert(prev.next_in_node == global_name); |
| | 814 | assert(prev.symtab_index.ptr(elf).node == old_node); |
| | 815 | prev.next_in_node = global_ptr.next_in_node; |
| | 816 | } else { |
| | 817 | // We're the start of the linked list, so we need to change the head. |
| | 818 | if (global_ptr.next_in_node == .empty) { |
| | 819 | assert(elf.node_global_symbols.fetchSwapRemove(old_node).?.value == global_name); |
| | 820 | } else { |
| | 821 | elf.node_global_symbols.getPtr(old_node).?.* = global_ptr.next_in_node; |
| 364 | } | 822 | } |
| | 823 | } |
| | 824 | } else { |
| | 825 | assert(global_ptr.next_in_node == .empty); |
| | 826 | assert(global_ptr.prev_in_node == .empty); |
| | 827 | } |
| 365 | | 828 | |
| 366 | if (elf.si.dynsym == .null) return; | 829 | global_ptr.symtab_index.ptr(elf).node = new.node; |
| 367 | const dsi = elf.dynsym.count(); | 830 | |
| 368 | try elf.dynsym.putNoClobber(gpa, si, {}); | 831 | const old_head: String(.strtab) = old_head: { |
| 369 | const name_dynstr_entry = try elf.string(.dynstr, opts.name); | 832 | if (new.node == .none) break :old_head .empty; |
| 370 | switch (elf.shdrPtr(elf.si.dynsym.shndx(elf))) { | 833 | const gop = elf.node_global_symbols.getOrPutAssumeCapacity(new.node); |
| 371 | inline else => |shdr| { | 834 | const old_head: String(.strtab) = if (gop.found_existing) gop.value_ptr.* else .empty; |
| 372 | const old_size = elf.targetLoad(&shdr.size); | 835 | gop.value_ptr.* = global_name; |
| 373 | const ent_size = elf.targetLoad(&shdr.entsize); | 836 | break :old_head old_head; |
| 374 | const new_size = ent_size * elf.dynsym.count(); | 837 | }; |
| 375 | if (new_size > old_size) { | 838 | |
| 376 | elf.targetStore(&shdr.size, @intCast(new_size)); | 839 | global_ptr.prev_in_node = .empty; |
| 377 | const dynsym_ni = elf.si.dynsym.node(elf); | 840 | global_ptr.next_in_node = old_head; |
| 378 | _, const node_size = dynsym_ni.location(&elf.mf).resolve(&elf.mf); | 841 | |
| 379 | if (new_size > node_size) try dynsym_ni.resize( | 842 | if (old_head != .empty) { |
| 380 | &elf.mf, | 843 | const old_head_ptr = elf.globalByName(old_head).?; |
| 381 | gpa, | 844 | assert(old_head_ptr.symtab_index.ptr(elf).node == new.node); |
| 382 | new_size +| new_size / MappedFile.growth_factor, | 845 | assert(old_head_ptr.prev_in_node == .empty); |
| 383 | ); | 846 | old_head_ptr.prev_in_node = global_name; |
| 384 | } | 847 | } |
| | 848 | |
| | 849 | // Now for the easy bit where we actually update the symtab entry. |
| | 850 | switch (elf.symPtr(global_ptr.symtab_index)) { |
| | 851 | inline else => |sym| { |
| | 852 | // Don't bother with `sym.value` here: it'll be updated by `flushMoved`. |
| | 853 | elf.targetStore(&sym.size, @intCast(new.size)); |
| | 854 | elf.targetStore(&sym.shndx, new.shndx.toSection().?); |
| | 855 | const old_bind = elf.targetLoad(&sym.info).bind; |
| | 856 | elf.targetStore(&sym.info, .{ |
| | 857 | .type = new.type, |
| | 858 | .bind = old_bind, |
| | 859 | }); |
| | 860 | }, |
| | 861 | } |
| | 862 | |
| | 863 | // ...and also the dynsym entry if there is one. |
| | 864 | if (global_ptr.dynsym_index != 0) switch (elf.dynsymPtr(global_ptr.dynsym_index)) { |
| | 865 | inline else => |sym| { |
| | 866 | // Don't bother with `sym.value` here: it'll be updated by `flushMoved`. |
| | 867 | elf.targetStore(&sym.size, @intCast(new.size)); |
| | 868 | elf.targetStore(&sym.shndx, new.shndx.toSection().?); |
| | 869 | const old_bind = elf.targetLoad(&sym.info).bind; |
| | 870 | elf.targetStore(&sym.info, .{ |
| | 871 | .type = new.type, |
| | 872 | .bind = old_bind, |
| | 873 | }); |
| | 874 | }, |
| | 875 | }; |
| | 876 | |
| | 877 | global_ptr.flushMoved(elf, new.value); |
| | 878 | } |
| | 879 | /// When the same global symbol appears in two inputs---even if one symbol is defined and the other |
| | 880 | /// undefined---their visibility values are combined to determine the resulting visibility, which |
| | 881 | /// can also affect the bind of the symbol we output. |
| | 882 | fn mergeGlobalSymbolVisibility(elf: *Elf, global_ptr: *Symbol.Global, other_visibility: std.elf.STV, bind: enum { strong, weak }) void { |
| | 883 | const old_visibility: std.elf.STV = switch (elf.symPtr(global_ptr.symtab_index)) { |
| | 884 | inline else => |sym| elf.targetLoad(&sym.other).visibility, |
| | 885 | }; |
| | 886 | // The combined visibility is essentially the "strictest" of the two, with most strict being |
| | 887 | // INTERNAL, followed by HIDDEN, PROTECTED, DEFAULT. |
| | 888 | const new_visibility: std.elf.STV, const newly_hidden: bool = switch (old_visibility) { |
| | 889 | .INTERNAL => .{ .INTERNAL, false }, |
| | 890 | .HIDDEN => switch (other_visibility) { |
| | 891 | .INTERNAL => .{ .INTERNAL, false }, |
| | 892 | .HIDDEN, .PROTECTED, .DEFAULT => .{ .HIDDEN, false }, |
| | 893 | }, |
| | 894 | .PROTECTED => switch (other_visibility) { |
| | 895 | .INTERNAL => .{ .INTERNAL, true }, |
| | 896 | .HIDDEN => .{ .HIDDEN, true }, |
| | 897 | .PROTECTED, .DEFAULT => .{ .PROTECTED, false }, |
| | 898 | }, |
| | 899 | .DEFAULT => switch (other_visibility) { |
| | 900 | .INTERNAL => .{ .INTERNAL, true }, |
| | 901 | .HIDDEN => .{ .HIDDEN, true }, |
| | 902 | .PROTECTED => .{ .PROTECTED, false }, |
| | 903 | .DEFAULT => .{ .DEFAULT, false }, |
| | 904 | }, |
| | 905 | }; |
| | 906 | // If the symbol is HIDDEN/INTERNAL and we're emitting an ELF module (executable or shared |
| | 907 | // object), then the symbol should have binding STB_LOCAL in the output. Therefore, if we are |
| | 908 | // putting the global in this state for the first time---let's call it "demoting" the global to |
| | 909 | // STB_LOCAL---we need to update its bind in the symtab. |
| | 910 | const demote_to_local = newly_hidden and elf.ehdrField(.type) != .REL; |
| | 911 | switch (elf.symPtr(global_ptr.symtab_index)) { |
| | 912 | inline else => |sym, class| { |
| | 913 | const old_info = elf.targetLoad(&sym.info); |
| | 914 | const new_info: class.ElfN().Sym.Info = .{ |
| | 915 | .type = old_info.type, |
| | 916 | .bind = if (demote_to_local) b: { |
| | 917 | assert(old_info.bind != .LOCAL); |
| | 918 | break :b .LOCAL; |
| | 919 | } else if (old_info.bind == .LOCAL) .LOCAL else switch (bind) { |
| | 920 | .strong => .GLOBAL, |
| | 921 | .weak => .WEAK, |
| 385 | }, | 922 | }, |
| | 923 | }; |
| | 924 | elf.targetStore(&sym.other, .{ .visibility = new_visibility }); |
| | 925 | elf.targetStore(&sym.info, new_info); |
| | 926 | // also update dynsym |
| | 927 | if (global_ptr.dynsym_index != 0) { |
| | 928 | const dynsym = @field(elf.dynsymPtr(global_ptr.dynsym_index), @tagName(class)); |
| | 929 | elf.targetStore(&dynsym.other, .{ .visibility = new_visibility }); |
| | 930 | elf.targetStore(&dynsym.info, new_info); |
| 386 | } | 931 | } |
| 387 | switch (elf.dynsymSlice()) { | 932 | }, |
| 388 | inline else => |dynsyms, class| { | 933 | } |
| 389 | const Sym = class.ElfN().Sym; | 934 | if (demote_to_local) { |
| 390 | const dynsym = &dynsyms[dsi]; | 935 | // When demoting a global to STB_LOCAL, we need to move its symtab index so that it is with |
| 391 | dynsym.* = .{ | 936 | // the STB_LOCAL symbols instead of the global symbols. |
| 392 | .name = name_dynstr_entry, | 937 | elf.moveDemotedGlobal(global_ptr); |
| 393 | .value = @intCast(opts.value), | 938 | } |
| 394 | .size = @intCast(opts.size), | 939 | } |
| 395 | .info = .{ .type = opts.type, .bind = opts.bind }, | 940 | /// If a symbol which was STB_GLOBAL/STB_WEAK becomes STB_LOCAL (see `mergeGlobalSymbolVisibility`), |
| 396 | .other = .{ .visibility = opts.visibility }, | 941 | /// the symbol must be moved from the "globals" part of the symtab to the "locals" part, because ELF |
| 397 | .shndx = opts.shndx.toSection().?, | 942 | /// requires that all STB_LOCAL symbols in a symbol table appear before any global symbols. |
| 398 | }; | 943 | fn moveDemotedGlobal(elf: *Elf, global_ptr: *Symbol.Global) void { |
| 399 | if (target_endian != native_endian) std.mem.byteSwapAllFields(Sym, dynsym); | 944 | assert(elf.ehdrField(.type) != .REL); // demotion only happens when emitting an ELF module |
| 400 | }, | 945 | switch (elf.shdrPtr(.symtab)) { |
| | 946 | inline else => |shdr, class| { |
| | 947 | // `shdr.info` stores the index of the first global symbol. We are going to swap the |
| | 948 | // demoted symbol with that first global symbol, then increment that start index. |
| | 949 | const dest_index: Symbol.Index = @enumFromInt(elf.targetLoad(&shdr.info)); |
| | 950 | const src_index = global_ptr.symtab_index; |
| | 951 | |
| | 952 | // This global should currently be in the "global symbols" part of the symtab, since our |
| | 953 | // job is to move it *out* of that part: |
| | 954 | assert(@intFromEnum(src_index) >= @intFromEnum(dest_index)); |
| | 955 | |
| | 956 | elf.targetStore(&shdr.info, @intFromEnum(dest_index) + 1); |
| | 957 | |
| | 958 | if (src_index == dest_index) { |
| | 959 | // The demoted global was already the first global, so we don't need to do any swap. |
| | 960 | return; |
| 401 | } | 961 | } |
| 402 | | 962 | |
| 403 | if (opts.type != .FUNC or opts.shndx != .UNDEF) return; | 963 | const src_sym_ptr = @field(elf.symPtr(src_index), @tagName(class)); |
| 404 | const plt_index: u32 = @intCast(elf.got.plt.count()); | 964 | const dest_sym_ptr = @field(elf.symPtr(dest_index), @tagName(class)); |
| 405 | try elf.got.plt.putNoClobber(gpa, si, {}); | | |
| 406 | switch (elf.ehdrField(.machine)) { | | |
| 407 | else => |machine| @panic(@tagName(machine)), | | |
| 408 | .X86_64 => { | | |
| 409 | const plt_ni = elf.si.plt.node(elf); | | |
| 410 | _, const plt_node_size = plt_ni.location(&elf.mf).resolve(&elf.mf); | | |
| 411 | const plt_addr = plt_addr: switch (elf.shdrPtr(elf.si.plt.shndx(elf))) { | | |
| 412 | inline else => |shdr| { | | |
| 413 | const old_size = 16 * (1 + plt_index); | | |
| 414 | const new_size = old_size + 16; | | |
| 415 | elf.targetStore(&shdr.size, new_size); | | |
| 416 | if (new_size > plt_node_size) try plt_ni.resize( | | |
| 417 | &elf.mf, | | |
| 418 | gpa, | | |
| 419 | new_size +| new_size / MappedFile.growth_factor, | | |
| 420 | ); | | |
| 421 | const plt_slice = plt_ni.slice(&elf.mf)[old_size..new_size]; | | |
| 422 | @memcpy(plt_slice, &[16]u8{ | | |
| 423 | 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 | | |
| 424 | 0x68, 0x00, 0x00, 0x00, 0x00, // push $0x0 | | |
| 425 | 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp 0 | | |
| 426 | 0x66, 0x90, // xchg %ax,%ax | | |
| 427 | }); | | |
| 428 | std.mem.writeInt(u32, plt_slice[5..][0..4], plt_index, target_endian); | | |
| 429 | std.mem.writeInt( | | |
| 430 | i32, | | |
| 431 | plt_slice[10..][0..4], | | |
| 432 | 2 - @as(i32, @intCast(new_size)), | | |
| 433 | target_endian, | | |
| 434 | ); | | |
| 435 | break :plt_addr elf.targetLoad(&shdr.addr) + old_size; | | |
| 436 | }, | | |
| 437 | }; | | |
| 438 | | 965 | |
| 439 | const got_plt_shndx = elf.si.got_plt.shndx(elf); | 966 | const this_name: String(.strtab) = @enumFromInt(elf.targetLoad(&src_sym_ptr.name)); |
| 440 | const got_plt_ni = elf.si.got_plt.node(elf); | 967 | assert(elf.globalByName(this_name).? == global_ptr); |
| 441 | _, const got_plt_node_size = got_plt_ni.location(&elf.mf).resolve(&elf.mf); | 968 | if (global_ptr.symtab_index.ptr(elf).first_target_reloc != .none) { |
| 442 | const got_plt_addr = got_plt_addr: switch (elf.shdrPtr(got_plt_shndx)) { | 969 | // This symbol's index is changing, so queue an update of relocs targeting it. |
| 443 | inline else => |shdr, class| { | 970 | elf.changed_symtab_index.putAssumeCapacity(this_name, {}); |
| 444 | const Addr = class.ElfN().Addr; | 971 | } |
| 445 | const addr_size = @sizeOf(Addr); | 972 | |
| 446 | const old_size = addr_size * (3 + plt_index); | 973 | const other_name: String(.strtab) = @enumFromInt(elf.targetLoad(&dest_sym_ptr.name)); |
| 447 | const new_size = old_size + addr_size; | 974 | const other_global_ptr = elf.globalByName(other_name).?; |
| 448 | elf.targetStore(&shdr.size, new_size); | 975 | assert(other_global_ptr.symtab_index == dest_index); |
| 449 | if (new_size > got_plt_node_size) try got_plt_ni.resize( | 976 | if (other_global_ptr.symtab_index.ptr(elf).first_target_reloc != .none) { |
| 450 | &elf.mf, | 977 | // This other symbol's index is changing, so queue an update of relocs targeting it. |
| 451 | gpa, | 978 | elf.changed_symtab_index.putAssumeCapacity(other_name, {}); |
| 452 | new_size +| new_size / MappedFile.growth_factor, | 979 | } |
| 453 | ); | 980 | |
| 454 | std.mem.writeInt( | 981 | // First swap the symtab entries... |
| 455 | Addr, | 982 | std.mem.swap(class.ElfN().Sym, src_sym_ptr, dest_sym_ptr); |
| 456 | got_plt_ni.slice(&elf.mf)[old_size..][0..addr_size], | 983 | // ...then the `elf.symtab` metadata... |
| 457 | @intCast(plt_addr), | 984 | std.mem.swap(Symbol, src_index.ptr(elf), dest_index.ptr(elf)); |
| 458 | target_endian, | 985 | // ...then update the `elf.globals` tracking. |
| 459 | ); | 986 | global_ptr.symtab_index = dest_index; |
| 460 | break :got_plt_addr elf.targetLoad(&shdr.addr) + old_size; | 987 | other_global_ptr.symtab_index = src_index; |
| 461 | }, | 988 | |
| 462 | }; | 989 | // We also need to get rid of the dynsym entry if there is one. For simplicity, just |
| | 990 | // replace it with a dummy entry which will never be used and will not cause problems. |
| | 991 | // TODO: we should have a free-list of dynsym slots so that other symbols can go here. |
| | 992 | // TODO: it would also be best to just avoid having gaps in the dynsym altogether. |
| | 993 | if (global_ptr.dynsym_index != 0) { |
| | 994 | const dynsym = @field(elf.dynsymPtr(global_ptr.dynsym_index), @tagName(class)); |
| | 995 | dynsym.* = .{ |
| | 996 | .name = @intFromEnum(String(.dynstr).empty), |
| | 997 | .value = 0, |
| | 998 | .size = 0, |
| | 999 | .info = .{ |
| | 1000 | .type = .NOTYPE, |
| | 1001 | // STB_WEAK is important: we mustn't cause a dynamic linker error if the |
| | 1002 | // symbol can't be resolved. |
| | 1003 | .bind = .WEAK, |
| | 1004 | }, |
| | 1005 | // SHN_UNDEF is important: we mustn't define this symbol for other DSOs. |
| | 1006 | .shndx = std.elf.SHN_UNDEF, |
| | 1007 | .other = .{ .visibility = .DEFAULT }, |
| | 1008 | }; |
| | 1009 | if (elf.targetEndian() != native_endian) { |
| | 1010 | std.mem.byteSwapAllFields(class.ElfN().Sym, dynsym); |
| | 1011 | } |
| | 1012 | } |
| | 1013 | }, |
| | 1014 | } |
| | 1015 | } |
| | 1016 | fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void { |
| | 1017 | const target_endian = elf.targetEndian(); |
| | 1018 | const plt_index: u32 = @intCast(elf.got.plt.count()); |
| | 1019 | elf.got.plt.putAssumeCapacityNoClobber(.global(global_name), {}); |
| | 1020 | switch (elf.ehdrField(.machine)) { |
| | 1021 | else => |machine| @panic(@tagName(machine)), |
| | 1022 | .X86_64 => { |
| | 1023 | const plt_ni = elf.shndx.plt.get(elf).ni; |
| | 1024 | const plt_addr = plt_addr: switch (elf.shdrPtr(elf.shndx.plt)) { |
| | 1025 | inline else => |shdr| { |
| | 1026 | const old_size = 16 * (1 + plt_index); |
| | 1027 | assert(elf.targetLoad(&shdr.size) == old_size); |
| | 1028 | elf.targetStore(&shdr.size, old_size + 16); |
| | 1029 | const plt_slice = plt_ni.slice(&elf.mf)[old_size..][0..16]; |
| | 1030 | @memcpy(plt_slice, &[16]u8{ |
| | 1031 | 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 |
| | 1032 | 0x68, 0x00, 0x00, 0x00, 0x00, // push $0x0 |
| | 1033 | 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp 0 |
| | 1034 | 0x66, 0x90, // xchg %ax,%ax |
| | 1035 | }); |
| | 1036 | std.mem.writeInt(u32, plt_slice[5..][0..4], plt_index, target_endian); |
| | 1037 | std.mem.writeInt( |
| | 1038 | i32, |
| | 1039 | plt_slice[10..][0..4], |
| | 1040 | -@as(i32, @intCast(old_size + 14)), |
| | 1041 | target_endian, |
| | 1042 | ); |
| | 1043 | break :plt_addr elf.targetLoad(&shdr.addr) + old_size; |
| | 1044 | }, |
| | 1045 | }; |
| | 1046 | |
| | 1047 | const got_plt_shndx = elf.shndx.got_plt; |
| | 1048 | const got_plt_ni = elf.shndx.got_plt.get(elf).ni; |
| | 1049 | const got_plt_addr = got_plt_addr: switch (elf.shdrPtr(got_plt_shndx)) { |
| | 1050 | inline else => |shdr, class| { |
| | 1051 | const ent_size = @sizeOf(class.ElfN().Addr); |
| | 1052 | const old_size = ent_size * (3 + plt_index); |
| | 1053 | elf.targetStore(&shdr.size, old_size + ent_size); |
| | 1054 | std.mem.writeInt( |
| | 1055 | class.ElfN().Addr, |
| | 1056 | got_plt_ni.slice(&elf.mf)[old_size..][0..ent_size], |
| | 1057 | @intCast(plt_addr), |
| | 1058 | target_endian, |
| | 1059 | ); |
| | 1060 | break :got_plt_addr elf.targetLoad(&shdr.addr) + old_size; |
| | 1061 | }, |
| | 1062 | }; |
| 463 | | 1063 | |
| 464 | const plt_sec_ni = elf.si.plt_sec.node(elf); | 1064 | const plt_sec_ni = elf.shndx.plt_sec.get(elf).ni; |
| 465 | _, const plt_sec_node_size = plt_sec_ni.location(&elf.mf).resolve(&elf.mf); | 1065 | switch (elf.shdrPtr(elf.shndx.plt_sec)) { |
| 466 | switch (elf.shdrPtr(elf.si.plt_sec.shndx(elf))) { | 1066 | inline else => |shdr| { |
| 467 | inline else => |shdr| { | 1067 | const old_size = 16 * plt_index; |
| 468 | const old_size = 16 * plt_index; | 1068 | elf.targetStore(&shdr.size, old_size + 16); |
| 469 | const new_size = old_size + 16; | 1069 | const plt_sec_slice = plt_sec_ni.slice(&elf.mf)[old_size..][0..16]; |
| 470 | elf.targetStore(&shdr.size, new_size); | 1070 | @memcpy(plt_sec_slice, &[16]u8{ |
| 471 | if (new_size > plt_sec_node_size) try plt_sec_ni.resize( | 1071 | 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 |
| 472 | &elf.mf, | 1072 | 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0(%rip) |
| 473 | gpa, | 1073 | 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00, // nopw 0x0(%rax,%rax,1) |
| 474 | new_size +| new_size / MappedFile.growth_factor, | 1074 | }); |
| 475 | ); | 1075 | std.mem.writeInt( |
| 476 | const plt_sec_slice = plt_sec_ni.slice(&elf.mf)[old_size..new_size]; | 1076 | i32, |
| 477 | @memcpy(plt_sec_slice, &[16]u8{ | 1077 | plt_sec_slice[6..][0..4], |
| 478 | 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 | 1078 | @intCast(@as(i64, @bitCast( |
| 479 | 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0(%rip) | 1079 | got_plt_addr -% (elf.targetLoad(&shdr.addr) + old_size + 10), |
| 480 | 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00, // nopw 0x0(%rax,%rax,1) | 1080 | ))), |
| 481 | }); | 1081 | target_endian, |
| 482 | std.mem.writeInt( | 1082 | ); |
| 483 | i32, | 1083 | }, |
| 484 | plt_sec_slice[6..][0..4], | 1084 | } |
| 485 | @intCast(@as(i64, @bitCast( | | |
| 486 | got_plt_addr -% (elf.targetLoad(&shdr.addr) + old_size + 10), | | |
| 487 | ))), | | |
| 488 | target_endian, | | |
| 489 | ); | | |
| 490 | }, | | |
| 491 | } | | |
| 492 | | 1085 | |
| 493 | const rela_plt_si = got_plt_shndx.get(elf).rela_si; | 1086 | const rela_plt_shndx = got_plt_shndx.get(elf).rela_shndx; |
| 494 | const rela_plt_ni = rela_plt_si.node(elf); | 1087 | const rela_plt_ni = rela_plt_shndx.get(elf).ni; |
| 495 | _, const rela_plt_node_size = rela_plt_ni.location(&elf.mf).resolve(&elf.mf); | 1088 | switch (elf.shdrPtr(rela_plt_shndx)) { |
| 496 | switch (elf.shdrPtr(rela_plt_si.shndx(elf))) { | 1089 | inline else => |shdr, class| { |
| 497 | inline else => |shdr, class| { | 1090 | const Rela = class.ElfN().Rela; |
| 498 | const Rela = class.ElfN().Rela; | 1091 | const rela_size = elf.targetLoad(&shdr.entsize); |
| 499 | const rela_size = elf.targetLoad(&shdr.entsize); | 1092 | const old_size = rela_size * plt_index; |
| 500 | const old_size = rela_size * plt_index; | 1093 | const new_size = old_size + rela_size; |
| 501 | const new_size = old_size + rela_size; | 1094 | elf.targetStore(&shdr.size, new_size); |
| 502 | elf.targetStore(&shdr.size, new_size); | 1095 | const rela: *Rela = @ptrCast(@alignCast( |
| 503 | if (new_size > rela_plt_node_size) try rela_plt_ni.resize( | 1096 | rela_plt_ni.slice(&elf.mf)[@intCast(old_size)..@intCast(new_size)], |
| 504 | &elf.mf, | 1097 | )); |
| 505 | gpa, | 1098 | rela.* = .{ |
| 506 | new_size +| new_size / MappedFile.growth_factor, | 1099 | .offset = @intCast(got_plt_addr), |
| 507 | ); | 1100 | .info = .{ |
| 508 | const rela: *Rela = @ptrCast(@alignCast( | 1101 | .type = @intFromEnum(std.elf.R_X86_64.JUMP_SLOT), |
| 509 | rela_plt_ni.slice(&elf.mf)[@intCast(old_size)..@intCast(new_size)], | 1102 | .sym = @intCast(dynsym_index), |
| 510 | )); | | |
| 511 | rela.* = .{ | | |
| 512 | .offset = @intCast(got_plt_addr), | | |
| 513 | .info = .{ | | |
| 514 | .type = @intFromEnum(std.elf.R_X86_64.JUMP_SLOT), | | |
| 515 | .sym = @intCast(dsi), | | |
| 516 | }, | | |
| 517 | .addend = 0, | | |
| 518 | }; | | |
| 519 | if (target_endian != native_endian) std.mem.byteSwapAllFields(Rela, rela); | | |
| 520 | }, | 1103 | }, |
| 521 | } | 1104 | .addend = 0, |
| 522 | try rela_plt_ni.resized(gpa, &elf.mf); | 1105 | }; |
| | 1106 | if (target_endian != native_endian) std.mem.byteSwapAllFields(Rela, rela); |
| 523 | }, | 1107 | }, |
| 524 | } | 1108 | } |
| 525 | } | 1109 | }, |
| | 1110 | } |
| | 1111 | } |
| 526 | | 1112 | |
| 527 | pub fn flushMoved(si: Symbol.Index, elf: *Elf, value: u64) void { | 1113 | const Symbol = struct { |
| 528 | switch (elf.symPtr(si)) { | 1114 | /// The node which this symbol's value is defined relative to. Possible values are: |
| 529 | inline else => |sym, class| { | 1115 | /// * `.none` for a SHN_ABS or SHN_UNDEF symbol |
| 530 | elf.targetStore(&sym.value, @intCast(value)); | 1116 | /// * A section (the symbol's value is that section's vaddr) |
| 531 | if (si == elf.si.entry) { | 1117 | /// * An input section (the symbol's value is some vaddr in that input section) |
| 532 | @branchHint(.unlikely); | 1118 | /// * A NAV, UAV, or lazy code/data (the symbol's value is exactly the vaddr of that node) |
| 533 | @field(elf.ehdrPtr(), @tagName(class)).entry = sym.value; | 1119 | node: MappedFile.Node.Index, |
| 534 | } | 1120 | |
| 535 | }, | 1121 | /// The head of a linked list of relocations targeting this symbol. |
| | 1122 | first_target_reloc: Reloc.Index, |
| | 1123 | |
| | 1124 | const Global = struct { |
| | 1125 | /// The current index of the symtab entry for this global symbol. |
| | 1126 | symtab_index: Symbol.Index, |
| | 1127 | /// The current index of the dynsym entry for this global symbol. If the global has been |
| | 1128 | /// demoted to STB_LOCAL, it does not have a dynsym entry and this field is set to 0. |
| | 1129 | dynsym_index: u32, |
| | 1130 | |
| | 1131 | /// The next entry in a linked list of global symbols with the same `Symbol.node` value. |
| | 1132 | /// |
| | 1133 | /// If `node` is `.none`, this is `.empty`. |
| | 1134 | next_in_node: String(.strtab), |
| | 1135 | /// The previous entry in a linked list of global symbols with the same `Symbol.node` value. |
| | 1136 | /// |
| | 1137 | /// If `node` is `.none`, this is `.empty`. |
| | 1138 | prev_in_node: String(.strtab), |
| | 1139 | |
| | 1140 | /// Like `Symbol.Index.flushMoved`, but also updates the dynamic symbol table if necessary. |
| | 1141 | fn flushMoved(g: *const Global, elf: *Elf, value: u64) void { |
| | 1142 | g.symtab_index.flushMoved(elf, value); |
| | 1143 | if (g.dynsym_index != 0) { |
| | 1144 | switch (elf.dynsymPtr(g.dynsym_index)) { |
| | 1145 | inline else => |sym| elf.targetStore(&sym.value, @intCast(value)), |
| | 1146 | } |
| 536 | } | 1147 | } |
| 537 | si.applyLocationRelocs(elf); | | |
| 538 | si.applyTargetRelocs(elf); | | |
| 539 | } | 1148 | } |
| | 1149 | }; |
| | 1150 | |
| | 1151 | /// An index directly into the symtab. These values are not stable (global symbols are sometimes |
| | 1152 | /// moved to new locations in the symtab) and therefore should only be used ephemerally. |
| | 1153 | /// |
| | 1154 | /// Local symbols *do* have stable indices into the symtab; see `LocalIndex`. |
| | 1155 | /// |
| | 1156 | /// For a stable reference to an arbitrary symbol, see `Id`. |
| | 1157 | const Index = enum(u32) { |
| | 1158 | null = 0, |
| | 1159 | _, |
| 540 | | 1160 | |
| 541 | pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void { | 1161 | fn flushMoved(si: Symbol.Index, elf: *Elf, value: u64) void { |
| 542 | if (elf.ehdrField(.type) == .REL) return; | 1162 | switch (elf.symPtr(si)) { |
| 543 | switch (si.get(elf).loc_relocs) { | 1163 | inline else => |sym| elf.targetStore(&sym.value, @intCast(value)), |
| 544 | .none => {}, | 1164 | } |
| 545 | else => |loc_relocs| for (elf.relocs.items[@intFromEnum(loc_relocs)..]) |*reloc| { | 1165 | if (elf.ehdrField(.type) != .REL) { |
| 546 | if (reloc.loc != si) break; | 1166 | var ri = si.ptr(elf).first_target_reloc; |
| | 1167 | while (ri != .none) { |
| | 1168 | const reloc = ri.get(elf); |
| | 1169 | assert(reloc.target.index(elf) == si); |
| 547 | reloc.apply(elf); | 1170 | reloc.apply(elf); |
| 548 | }, | 1171 | ri = reloc.next; |
| | 1172 | } |
| 549 | } | 1173 | } |
| 550 | } | 1174 | } |
| | 1175 | fn ptr(si: Symbol.Index, elf: *Elf) *Symbol { |
| | 1176 | return &elf.symtab.items[@intFromEnum(si)]; |
| | 1177 | } |
| | 1178 | }; |
| 551 | | 1179 | |
| 552 | pub fn applyTargetRelocs(si: Symbol.Index, elf: *Elf) void { | 1180 | /// A `LocalIndex` is a raw index into the symtab like `Index`, but it guarantees that the |
| 553 | if (elf.ehdrField(.type) == .REL) return; | 1181 | /// symbol in question has STB_LOCAL binding, which guarantees that its symtab index is stable |
| 554 | var ri = si.get(elf).target_relocs; | 1182 | /// so can be stored long-term without needing to be updated |
| 555 | while (ri != .none) { | 1183 | /// |
| 556 | const reloc = ri.get(elf); | 1184 | /// This is because symbols which have STB_LOCAL binding in the output file gain fixed symtab |
| 557 | assert(reloc.target == si); | 1185 | /// indices, thanks to a combination of a few factors: |
| 558 | reloc.apply(elf); | 1186 | /// * We never remove STB_LOCAL symbols |
| 559 | ri = reloc.next; | 1187 | /// * There is no symbol ordering requirement *within* the leading range of STB_LOCAL symbols |
| 560 | } | 1188 | /// * A symbol visibility which demotes a global to STB_LOCAL binding can never be reverted by |
| | 1189 | /// a subsequent operation (different visibilities resolve to the "strictest" one) |
| | 1190 | const LocalIndex = enum(u32) { |
| | 1191 | null = 0, |
| | 1192 | _, |
| | 1193 | |
| | 1194 | fn index(li: LocalIndex) Index { |
| | 1195 | return @enumFromInt(@intFromEnum(li)); |
| 561 | } | 1196 | } |
| | 1197 | }; |
| 562 | | 1198 | |
| 563 | pub fn deleteLocationRelocs(si: Symbol.Index, elf: *Elf) void { | 1199 | /// Opaque, stable identifier for a symbol. Does not necessarily equal the index into the symtab. |
| 564 | const sym = si.get(elf); | 1200 | const Id = packed struct(u32) { |
| 565 | for (elf.relocs.items[@intFromEnum(sym.loc_relocs)..]) |*reloc| { | 1201 | kind: enum(u1) { local, global }, |
| 566 | if (reloc.loc != si) break; | 1202 | raw: u31, |
| 567 | reloc.delete(elf); | 1203 | |
| 568 | } | 1204 | const @"null": Symbol.Id = .local(.null); |
| 569 | sym.loc_relocs = .none; | 1205 | |
| | 1206 | fn local(lsi: Symbol.LocalIndex) Symbol.Id { |
| | 1207 | return .{ .kind = .local, .raw = @intCast(@intFromEnum(lsi)) }; |
| | 1208 | } |
| | 1209 | fn global(name: String(.strtab)) Symbol.Id { |
| | 1210 | return .{ .kind = .global, .raw = @intCast(@intFromEnum(name)) }; |
| | 1211 | } |
| | 1212 | fn unwrap(s: Symbol.Id) union(enum) { |
| | 1213 | local: Symbol.LocalIndex, |
| | 1214 | global: String(.strtab), |
| | 1215 | } { |
| | 1216 | return switch (s.kind) { |
| | 1217 | .local => .{ .local = @enumFromInt(s.raw) }, |
| | 1218 | .global => .{ .global = @enumFromInt(s.raw) }, |
| | 1219 | }; |
| | 1220 | } |
| | 1221 | |
| | 1222 | fn toTypeErased(s: Symbol.Id) link.File.SymbolId { |
| | 1223 | return @enumFromInt(@as(u32, @bitCast(s))); |
| | 1224 | } |
| | 1225 | fn fromTypeErased(s: link.File.SymbolId) Symbol.Id { |
| | 1226 | return @bitCast(@intFromEnum(s)); |
| | 1227 | } |
| | 1228 | |
| | 1229 | fn index(s: Symbol.Id, elf: *const Elf) Symbol.Index { |
| | 1230 | return switch (s.unwrap()) { |
| | 1231 | .local => |lsi| lsi.index(), |
| | 1232 | .global => |name| elf.globalByName(name).?.symtab_index, |
| | 1233 | }; |
| | 1234 | } |
| | 1235 | |
| | 1236 | fn value(s: Symbol.Id, elf: *Elf) u64 { |
| | 1237 | return switch (elf.symPtr(s.index(elf))) { |
| | 1238 | inline else => |sym| elf.targetLoad(&sym.value), |
| | 1239 | }; |
| | 1240 | } |
| | 1241 | |
| | 1242 | /// Returns `true` if the target of `s` has moved, meaning the symbol's value will change at |
| | 1243 | /// some point due to a call to `flushMoved`. |
| | 1244 | fn hasMoved(s: Symbol.Id, elf: *Elf) bool { |
| | 1245 | const node = s.index(elf).ptr(elf).node; |
| | 1246 | if (node == .none) return false; |
| | 1247 | return node.hasMoved(&elf.mf); |
| 570 | } | 1248 | } |
| 571 | }; | 1249 | }; |
| | 1250 | }; |
| 572 | | 1251 | |
| 573 | pub const Known = struct { | 1252 | fn globalByName(elf: *const Elf, name: String(.strtab)) ?*Symbol.Global { |
| 574 | comptime symtab: Symbol.Index = .symtab, | 1253 | if (elf.globals.strong_def.getPtr(name)) |ptr| return ptr; |
| 575 | comptime shstrtab: Symbol.Index = .shstrtab, | 1254 | if (elf.globals.weak_def.getPtr(name)) |ptr| return ptr; |
| 576 | comptime strtab: Symbol.Index = .strtab, | 1255 | if (elf.globals.strong_undef.getPtr(name)) |ptr| return ptr; |
| 577 | comptime rodata: Symbol.Index = .rodata, | 1256 | if (elf.globals.weak_undef.getPtr(name)) |ptr| return ptr; |
| 578 | comptime text: Symbol.Index = .text, | 1257 | return null; |
| 579 | comptime data: Symbol.Index = .data, | 1258 | } |
| 580 | comptime data_rel_ro: Symbol.Index = .data_rel_ro, | 1259 | |
| 581 | comptime got: Symbol.Index = .got, | 1260 | pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId { |
| 582 | comptime got_plt: Symbol.Index = .got_plt, | 1261 | const lsi: Symbol.LocalIndex = switch (elf.getNode(Node.fromAtom(atom))) { |
| 583 | comptime plt: Symbol.Index = .plt, | 1262 | .file, |
| 584 | comptime plt_sec: Symbol.Index = .plt_sec, | 1263 | .ehdr, |
| 585 | dynsym: Symbol.Index, | 1264 | .shdr, |
| 586 | dynstr: Symbol.Index, | 1265 | .segment, |
| 587 | dynamic: Symbol.Index, | 1266 | .section, |
| 588 | tdata: Symbol.Index, | 1267 | .input_section, |
| 589 | entry: Symbol.Index, | 1268 | => unreachable, |
| | 1269 | |
| | 1270 | inline .nav, |
| | 1271 | .uav, |
| | 1272 | .lazy_code, |
| | 1273 | .lazy_const_data, |
| | 1274 | => |i| i.symbol(elf), |
| 590 | }; | 1275 | }; |
| | 1276 | const s: Symbol.Id = .local(lsi); |
| | 1277 | return s.toTypeErased(); |
| | 1278 | } |
| | 1279 | pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !link.File.SymbolId { |
| | 1280 | const gpa = elf.base.comp.gpa; |
| 591 | | 1281 | |
| 592 | comptime { | 1282 | try elf.ensureUnusedSymbolCapacity(1, .all_local); |
| 593 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 16); | 1283 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| | 1284 | try elf.lazy.getPtr(lazy.kind).map.ensureUnusedCapacity(gpa, 1); |
| | 1285 | |
| | 1286 | const gop = elf.lazy.getPtr(lazy.kind).map.getOrPutAssumeCapacity(lazy.ty); |
| | 1287 | if (!gop.found_existing) { |
| | 1288 | const shndx: Section.Index, const sym_type: std.elf.STT = switch (lazy.kind) { |
| | 1289 | .code => .{ .text, .FUNC }, |
| | 1290 | .const_data => .{ .rodata, .OBJECT }, |
| | 1291 | }; |
| | 1292 | const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{}); |
| | 1293 | var name_buf: [64]u8 = undefined; |
| | 1294 | const name = std.fmt.bufPrint( |
| | 1295 | &name_buf, |
| | 1296 | "__lazy_{t}_{d}", |
| | 1297 | .{ lazy.kind, @intFromEnum(lazy.ty) }, |
| | 1298 | ) catch unreachable; |
| | 1299 | gop.value_ptr.* = .{ |
| | 1300 | .lsi = elf.addLocalSymbolAssumeCapacity(.{ |
| | 1301 | .node = node, |
| | 1302 | .name = try elf.string(.strtab, name), |
| | 1303 | .value = 0, |
| | 1304 | .size = 0, |
| | 1305 | .type = sym_type, |
| | 1306 | .shndx = shndx, |
| | 1307 | }), |
| | 1308 | .first_reloc = .none, |
| | 1309 | }; |
| | 1310 | elf.nodes.appendAssumeCapacity(switch (lazy.kind) { |
| | 1311 | .code => .{ .lazy_code = @enumFromInt(gop.index) }, |
| | 1312 | .const_data => .{ .lazy_const_data = @enumFromInt(gop.index) }, |
| | 1313 | }); |
| | 1314 | elf.synth_prog_node.increaseEstimatedTotalItems(1); |
| | 1315 | } |
| | 1316 | const s: Symbol.Id = .local(gop.value_ptr.lsi); |
| | 1317 | return s.toTypeErased(); |
| | 1318 | } |
| | 1319 | pub fn externSymbol(elf: *Elf, opts: struct { |
| | 1320 | name: []const u8, |
| | 1321 | lib_name: ?[]const u8, |
| | 1322 | type: std.elf.STT, |
| | 1323 | linkage: std.lang.GlobalLinkage = .strong, |
| | 1324 | visibility: std.lang.SymbolVisibility = .default, |
| | 1325 | }) !link.File.SymbolId { |
| | 1326 | try elf.ensureUnusedSymbolCapacity(1, .maybe_global); |
| | 1327 | const symbol = elf.addGlobalSymbolAssumeCapacity(.{ |
| | 1328 | .node = .none, |
| | 1329 | .name = try .string(elf, opts.name), |
| | 1330 | .lib_name = opts.lib_name, |
| | 1331 | .value = 0, |
| | 1332 | .size = 0, |
| | 1333 | .type = opts.type, |
| | 1334 | .bind = switch (opts.linkage) { |
| | 1335 | .internal => @panic("TODO internal extern symbol"), |
| | 1336 | .strong => .strong, |
| | 1337 | .weak => .weak, |
| | 1338 | .link_once => return error.LinkOnceUnsupported, |
| | 1339 | }, |
| | 1340 | .visibility = switch (opts.visibility) { |
| | 1341 | .default => .DEFAULT, |
| | 1342 | .hidden => .HIDDEN, |
| | 1343 | .protected => .PROTECTED, |
| | 1344 | }, |
| | 1345 | .shndx = .UNDEF, |
| | 1346 | }) catch |err| switch (err) { |
| | 1347 | error.MultipleDefinitions => unreachable, // shndx is undef |
| | 1348 | }; |
| | 1349 | return symbol.toTypeErased(); |
| | 1350 | } |
| | 1351 | pub fn addReloc( |
| | 1352 | elf: *Elf, |
| | 1353 | atom: link.File.AtomId, |
| | 1354 | offset: u64, |
| | 1355 | target: link.File.SymbolId, |
| | 1356 | addend: i64, |
| | 1357 | @"type": Reloc.Type, |
| | 1358 | ) !void { |
| | 1359 | const node: MappedFile.Node.Index = Node.fromAtom(atom); |
| | 1360 | try elf.ensureUnusedRelocCapacity(node, 1); |
| | 1361 | elf.addRelocAssumeCapacity(node, offset, .fromTypeErased(target), addend, @"type"); |
| | 1362 | } |
| | 1363 | pub fn navSymbol(elf: *Elf, nav_index: InternPool.Nav.Index) !link.File.SymbolId { |
| | 1364 | const zcu = elf.base.comp.zcu.?; |
| | 1365 | const ip = &zcu.intern_pool; |
| | 1366 | const nav = ip.getNav(nav_index); |
| | 1367 | if (nav.getExtern(ip)) |@"extern"| { |
| | 1368 | return elf.externSymbol(.{ |
| | 1369 | .name = @"extern".name.toSlice(ip), |
| | 1370 | .lib_name = @"extern".lib_name.toSlice(ip), |
| | 1371 | .type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded), |
| | 1372 | .linkage = @"extern".linkage, |
| | 1373 | .visibility = @"extern".visibility, |
| | 1374 | }); |
| | 1375 | } |
| | 1376 | const nmi = try elf.navMapIndex(zcu, nav_index); |
| | 1377 | const s: Symbol.Id = .local(nmi.symbol(elf)); |
| | 1378 | return s.toTypeErased(); |
| | 1379 | } |
| | 1380 | pub fn uavSymbol( |
| | 1381 | elf: *Elf, |
| | 1382 | uav_val: InternPool.Index, |
| | 1383 | uav_align: InternPool.Alignment, |
| | 1384 | ) !link.File.SymbolId { |
| | 1385 | const umi = try elf.uavMapIndex(uav_val, uav_align); |
| | 1386 | const s: Symbol.Id = .local(umi.symbol(elf)); |
| | 1387 | return s.toTypeErased(); |
| | 1388 | } |
| | 1389 | pub fn getNavVAddr( |
| | 1390 | elf: *Elf, |
| | 1391 | pt: Zcu.PerThread, |
| | 1392 | nav: InternPool.Nav.Index, |
| | 1393 | reloc_info: link.File.RelocInfo, |
| | 1394 | ) !u64 { |
| | 1395 | _ = pt; |
| | 1396 | return elf.getVAddr(reloc_info, try elf.navSymbol(nav)); |
| | 1397 | } |
| | 1398 | pub fn getUavVAddr( |
| | 1399 | elf: *Elf, |
| | 1400 | uav_val: InternPool.Index, |
| | 1401 | reloc_info: link.File.RelocInfo, |
| | 1402 | ) !u64 { |
| | 1403 | return elf.getVAddr(reloc_info, try elf.uavSymbol(uav_val, .none)); |
| | 1404 | } |
| | 1405 | pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target: link.File.SymbolId) !u64 { |
| | 1406 | const node: MappedFile.Node.Index = Node.fromAtom(reloc_info.parent.atom_index); |
| | 1407 | const target_sym: Symbol.Id = .fromTypeErased(target); |
| | 1408 | try elf.ensureUnusedRelocCapacity(node, 1); |
| | 1409 | elf.addRelocAssumeCapacity( |
| | 1410 | node, |
| | 1411 | reloc_info.offset, |
| | 1412 | target_sym, |
| | 1413 | reloc_info.addend, |
| | 1414 | .absAddr(elf), |
| | 1415 | ); |
| | 1416 | return target_sym.value(elf); |
| | 1417 | } |
| | 1418 | pub fn lowerUav( |
| | 1419 | elf: *Elf, |
| | 1420 | pt: Zcu.PerThread, |
| | 1421 | uav_val: InternPool.Index, |
| | 1422 | uav_align: InternPool.Alignment, |
| | 1423 | src_loc: Zcu.LazySrcLoc, |
| | 1424 | ) !codegen.SymbolResult { |
| | 1425 | _ = pt; |
| | 1426 | const umi = elf.uavMapIndex(uav_val, uav_align) catch |err| switch (err) { |
| | 1427 | error.OutOfMemory => |e| return e, |
| | 1428 | else => |e| return .{ .fail = try Zcu.ErrorMsg.create( |
| | 1429 | elf.base.comp.gpa, |
| | 1430 | src_loc, |
| | 1431 | "linker failed to update constant: {s}", |
| | 1432 | .{@errorName(e)}, |
| | 1433 | ) }, |
| | 1434 | }; |
| | 1435 | const s: Symbol.Id = .local(umi.symbol(elf)); |
| | 1436 | return .{ .sym_index = s.toTypeErased() }; |
| | 1437 | } |
| | 1438 | |
| | 1439 | const StringSection = enum { |
| | 1440 | shstrtab, |
| | 1441 | strtab, |
| | 1442 | dynstr, |
| | 1443 | fn shndx(s: StringSection, elf: *const Elf) Section.Index { |
| | 1444 | return switch (s) { |
| | 1445 | .strtab => .strtab, |
| | 1446 | .shstrtab => .shstrtab, |
| | 1447 | .dynstr => elf.shndx.dynstr, |
| | 1448 | }; |
| 594 | } | 1449 | } |
| 595 | }; | 1450 | }; |
| | 1451 | fn String(section: StringSection) type { |
| | 1452 | return enum(u32) { |
| | 1453 | empty = 0, |
| | 1454 | _, |
| | 1455 | |
| | 1456 | fn slice(str: @This(), elf: *Elf) [:0]const u8 { |
| | 1457 | const section_node = section.shndx(elf).get(elf).ni; |
| | 1458 | const overlong = section_node.sliceConst(&elf.mf)[@intFromEnum(str)..]; |
| | 1459 | return overlong[0..std.mem.findScalar(u8, overlong, 0).? :0]; |
| | 1460 | } |
| | 1461 | }; |
| | 1462 | } |
| | 1463 | fn string(elf: *Elf, comptime section: StringSection, key: []const u8) !String(section) { |
| | 1464 | const st: *StringTable = &@field(elf, @tagName(section)); |
| | 1465 | return @enumFromInt(try st.get(elf, section.shndx(elf), key)); |
| | 1466 | } |
| 596 | | 1467 | |
| 597 | pub const StringTable = struct { | 1468 | const StringTable = struct { |
| 598 | map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage), | 1469 | map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage), |
| 599 | | 1470 | |
| 600 | const Context = struct { | 1471 | const Context = struct { |
| ... | @@ -623,9 +1494,13 @@ pub const StringTable = struct { | ... | @@ -623,9 +1494,13 @@ pub const StringTable = struct { |
| 623 | } | 1494 | } |
| 624 | }; | 1495 | }; |
| 625 | | 1496 | |
| 626 | pub fn get(st: *StringTable, elf: *Elf, si: Symbol.Index, key: []const u8) !u32 { | 1497 | pub fn get(st: *StringTable, elf: *Elf, shndx: Section.Index, key: []const u8) !u32 { |
| | 1498 | // If we are in `initHeaders` the strtab might not be initalized yet, so we need to special |
| | 1499 | // case the empty string. |
| | 1500 | if (key.len == 0) return 0; |
| | 1501 | |
| 627 | const gpa = elf.base.comp.gpa; | 1502 | const gpa = elf.base.comp.gpa; |
| 628 | const ni = si.node(elf); | 1503 | const ni = shndx.get(elf).ni; |
| 629 | const slice_const = ni.sliceConst(&elf.mf); | 1504 | const slice_const = ni.sliceConst(&elf.mf); |
| 630 | const gop = try st.map.getOrPutContextAdapted( | 1505 | const gop = try st.map.getOrPutContextAdapted( |
| 631 | gpa, | 1506 | gpa, |
| ... | @@ -635,7 +1510,7 @@ pub const StringTable = struct { | ... | @@ -635,7 +1510,7 @@ pub const StringTable = struct { |
| 635 | ); | 1510 | ); |
| 636 | if (gop.found_existing) return gop.key_ptr.*; | 1511 | if (gop.found_existing) return gop.key_ptr.*; |
| 637 | try ni.resized(gpa, &elf.mf); | 1512 | try ni.resized(gpa, &elf.mf); |
| 638 | const old_size, const new_size = size: switch (elf.shdrPtr(si.shndx(elf))) { | 1513 | const old_size, const new_size = size: switch (elf.shdrPtr(shndx)) { |
| 639 | inline else => |shdr| { | 1514 | inline else => |shdr| { |
| 640 | const old_size: u32 = @intCast(elf.targetLoad(&shdr.size)); | 1515 | const old_size: u32 = @intCast(elf.targetLoad(&shdr.size)); |
| 641 | const new_size: u32 = @intCast(old_size + key.len + 1); | 1516 | const new_size: u32 = @intCast(old_size + key.len + 1); |
| ... | @@ -654,7 +1529,7 @@ pub const StringTable = struct { | ... | @@ -654,7 +1529,7 @@ pub const StringTable = struct { |
| 654 | } | 1529 | } |
| 655 | }; | 1530 | }; |
| 656 | | 1531 | |
| 657 | pub const GotIndex = enum(u32) { | 1532 | const GotIndex = enum(u32) { |
| 658 | none = std.math.maxInt(u32), | 1533 | none = std.math.maxInt(u32), |
| 659 | _, | 1534 | _, |
| 660 | | 1535 | |
| ... | @@ -671,12 +1546,12 @@ pub const GotIndex = enum(u32) { | ... | @@ -671,12 +1546,12 @@ pub const GotIndex = enum(u32) { |
| 671 | } | 1546 | } |
| 672 | }; | 1547 | }; |
| 673 | | 1548 | |
| 674 | pub const Reloc = extern struct { | 1549 | const Reloc = extern struct { |
| 675 | type: Reloc.Type, | 1550 | type: Reloc.Type, |
| 676 | prev: Reloc.Index, | 1551 | prev: Reloc.Index, |
| 677 | next: Reloc.Index, | 1552 | next: Reloc.Index, |
| 678 | loc: Symbol.Index, | 1553 | node: MappedFile.Node.Index, |
| 679 | target: Symbol.Index, | 1554 | target: Symbol.Id, |
| 680 | index: Section.RelIndex, | 1555 | index: Section.RelIndex, |
| 681 | offset: u64, | 1556 | offset: u64, |
| 682 | addend: i64, | 1557 | addend: i64, |
| ... | @@ -745,85 +1620,86 @@ pub const Reloc = extern struct { | ... | @@ -745,85 +1620,86 @@ pub const Reloc = extern struct { |
| 745 | | 1620 | |
| 746 | pub fn apply(reloc: *const Reloc, elf: *Elf) void { | 1621 | pub fn apply(reloc: *const Reloc, elf: *Elf) void { |
| 747 | assert(elf.ehdrField(.type) != .REL); | 1622 | assert(elf.ehdrField(.type) != .REL); |
| 748 | const loc_ni = reloc.loc.get(elf).ni; | 1623 | assert(reloc.node != .none); |
| 749 | switch (loc_ni) { | 1624 | if (reloc.node.hasMoved(&elf.mf) or reloc.target.hasMoved(elf)) { |
| 750 | .none => return, | 1625 | // There's no point applying the relocation now, because it will be re-applied by |
| 751 | else => |ni| if (ni.hasMoved(&elf.mf)) return, | 1626 | // `flushMoved` at some point anyway. |
| 752 | } | 1627 | return; |
| 753 | switch (reloc.target.get(elf).ni) { | | |
| 754 | .none => {}, | | |
| 755 | else => |ni| if (ni.hasMoved(&elf.mf)) return, | | |
| 756 | } | 1628 | } |
| 757 | const loc_slice = loc_ni.slice(&elf.mf)[@intCast(reloc.offset)..]; | 1629 | const node_vaddr: u64 = switch (elf.getNode(reloc.node)) { |
| | 1630 | .file => unreachable, |
| | 1631 | .ehdr => unreachable, |
| | 1632 | .shdr => unreachable, |
| | 1633 | .segment => unreachable, |
| | 1634 | .section => |shndx| shndx.vaddr(elf), |
| | 1635 | .input_section => |isi| isi.ptrConst(elf).vaddr, |
| | 1636 | inline .nav, |
| | 1637 | .uav, |
| | 1638 | .lazy_code, |
| | 1639 | .lazy_const_data, |
| | 1640 | => |i| Symbol.Id.local(i.symbol(elf)).value(elf), |
| | 1641 | }; |
| | 1642 | const dest_vaddr = node_vaddr + reloc.offset; |
| | 1643 | const dest_slice = reloc.node.slice(&elf.mf)[@intCast(reloc.offset)..]; |
| 758 | const target_endian = elf.targetEndian(); | 1644 | const target_endian = elf.targetEndian(); |
| 759 | switch (elf.symtabSlice()) { | 1645 | switch (elf.symPtr(reloc.target.index(elf))) { |
| 760 | inline else => |symtab, class| { | 1646 | inline else => |target_sym, class| { |
| 761 | const loc_sym = &symtab[@intFromEnum(reloc.loc)]; | 1647 | const target_value = elf.targetLoad(&target_sym.value) +% @as(u64, @bitCast(reloc.addend)); |
| 762 | const loc_shndx = elf.targetLoad(&loc_sym.shndx); | | |
| 763 | assert(loc_shndx != std.elf.SHN_UNDEF); | | |
| 764 | const target_sym = &symtab[@intFromEnum(reloc.target)]; | | |
| 765 | const target_value = | | |
| 766 | elf.targetLoad(&target_sym.value) +% @as(u64, @bitCast(reloc.addend)); | | |
| 767 | switch (elf.ehdrField(.machine)) { | 1648 | switch (elf.ehdrField(.machine)) { |
| 768 | else => |machine| @panic(@tagName(machine)), | 1649 | else => |machine| @panic(@tagName(machine)), |
| 769 | .X86_64 => switch (reloc.type.X86_64) { | 1650 | .X86_64 => switch (reloc.type.X86_64) { |
| 770 | else => |kind| @panic(@tagName(kind)), | 1651 | else => |kind| @panic(@tagName(kind)), |
| 771 | .@"64" => std.mem.writeInt( | 1652 | .@"64" => std.mem.writeInt( |
| 772 | u64, | 1653 | u64, |
| 773 | loc_slice[0..8], | 1654 | dest_slice[0..8], |
| 774 | target_value, | 1655 | target_value, |
| 775 | target_endian, | 1656 | target_endian, |
| 776 | ), | 1657 | ), |
| 777 | .PC32 => std.mem.writeInt( | 1658 | .PC32 => std.mem.writeInt( |
| 778 | i32, | 1659 | i32, |
| 779 | loc_slice[0..4], | 1660 | dest_slice[0..4], |
| 780 | @intCast(@as(i64, @bitCast(target_value -% | 1661 | @intCast(@as(i64, @bitCast(target_value -% dest_vaddr))), |
| 781 | (elf.targetLoad(&loc_sym.value) + reloc.offset)))), | | |
| 782 | target_endian, | 1662 | target_endian, |
| 783 | ), | 1663 | ), |
| 784 | .PLT32 => std.mem.writeInt( | 1664 | .PLT32 => std.mem.writeInt( |
| 785 | i32, | 1665 | i32, |
| 786 | loc_slice[0..4], | 1666 | dest_slice[0..4], |
| 787 | @intCast(@as(i64, @bitCast( | 1667 | @intCast(@as(i64, @bitCast(if (elf.got.plt.getIndex(reloc.target)) |plt_index| |
| 788 | if (elf.got.plt.getIndex(reloc.target)) |plt_index| | 1668 | elf.targetLoad(&@field( |
| 789 | elf.targetLoad(&@field( | 1669 | elf.shdrPtr(elf.shndx.plt_sec), |
| 790 | elf.shdrPtr(elf.si.plt_sec.shndx(elf)), | 1670 | @tagName(class), |
| 791 | @tagName(class), | 1671 | ).addr) +% 16 * plt_index +% |
| 792 | ).addr) +% 16 * plt_index +% | 1672 | @as(u64, @bitCast(reloc.addend)) -% dest_vaddr |
| 793 | @as(u64, @bitCast(reloc.addend)) -% | 1673 | else |
| 794 | (elf.targetLoad(&loc_sym.value) + reloc.offset) | 1674 | target_value -% dest_vaddr))), |
| 795 | else | | |
| 796 | target_value -% | | |
| 797 | (elf.targetLoad(&loc_sym.value) + reloc.offset), | | |
| 798 | ))), | | |
| 799 | target_endian, | 1675 | target_endian, |
| 800 | ), | 1676 | ), |
| 801 | .@"32" => std.mem.writeInt( | 1677 | .@"32" => std.mem.writeInt( |
| 802 | u32, | 1678 | u32, |
| 803 | loc_slice[0..4], | 1679 | dest_slice[0..4], |
| 804 | @intCast(target_value), | 1680 | @intCast(target_value), |
| 805 | target_endian, | 1681 | target_endian, |
| 806 | ), | 1682 | ), |
| 807 | .@"32S" => std.mem.writeInt( | 1683 | .@"32S" => std.mem.writeInt( |
| 808 | i32, | 1684 | i32, |
| 809 | loc_slice[0..4], | 1685 | dest_slice[0..4], |
| 810 | @intCast(@as(i64, @bitCast(target_value))), | 1686 | @intCast(@as(i64, @bitCast(target_value))), |
| 811 | target_endian, | 1687 | target_endian, |
| 812 | ), | 1688 | ), |
| 813 | .TLSLD => std.mem.writeInt( | 1689 | .TLSLD => std.mem.writeInt( |
| 814 | i32, | 1690 | i32, |
| 815 | loc_slice[0..4], | 1691 | dest_slice[0..4], |
| 816 | @intCast(@as(i64, @bitCast( | 1692 | @intCast(@as(i64, @bitCast( |
| 817 | elf.targetLoad(&symtab[@intFromEnum(elf.si.got)].value) +% | 1693 | elf.shndx.got.vaddr(elf) +% |
| 818 | @as(u64, @bitCast(reloc.addend)) +% | 1694 | @as(u64, @bitCast(reloc.addend)) +% |
| 819 | @as(u64, 8) * elf.got.tlsld.unwrap().? -% | 1695 | @as(u64, 8) * elf.got.tlsld.unwrap().? -% |
| 820 | (elf.targetLoad(&loc_sym.value) + reloc.offset), | 1696 | dest_vaddr, |
| 821 | ))), | 1697 | ))), |
| 822 | target_endian, | 1698 | target_endian, |
| 823 | ), | 1699 | ), |
| 824 | .DTPOFF32 => std.mem.writeInt( | 1700 | .DTPOFF32 => std.mem.writeInt( |
| 825 | i32, | 1701 | i32, |
| 826 | loc_slice[0..4], | 1702 | dest_slice[0..4], |
| 827 | @intCast(@as(i64, @bitCast(target_value))), | 1703 | @intCast(@as(i64, @bitCast(target_value))), |
| 828 | target_endian, | 1704 | target_endian, |
| 829 | ), | 1705 | ), |
| ... | @@ -833,14 +1709,14 @@ pub const Reloc = extern struct { | ... | @@ -833,14 +1709,14 @@ pub const Reloc = extern struct { |
| 833 | assert(elf.targetLoad(&ph.type) == .TLS); | 1709 | assert(elf.targetLoad(&ph.type) == .TLS); |
| 834 | std.mem.writeInt( | 1710 | std.mem.writeInt( |
| 835 | i32, | 1711 | i32, |
| 836 | loc_slice[0..4], | 1712 | dest_slice[0..4], |
| 837 | @intCast(@as(i64, @bitCast(target_value -% elf.targetLoad(&ph.memsz)))), | 1713 | @intCast(@as(i64, @bitCast(target_value -% elf.targetLoad(&ph.memsz)))), |
| 838 | target_endian, | 1714 | target_endian, |
| 839 | ); | 1715 | ); |
| 840 | }, | 1716 | }, |
| 841 | .SIZE32 => std.mem.writeInt( | 1717 | .SIZE32 => std.mem.writeInt( |
| 842 | u32, | 1718 | u32, |
| 843 | loc_slice[0..4], | 1719 | dest_slice[0..4], |
| 844 | @intCast( | 1720 | @intCast( |
| 845 | elf.targetLoad(&target_sym.size) +% @as(u64, @bitCast(reloc.addend)), | 1721 | elf.targetLoad(&target_sym.size) +% @as(u64, @bitCast(reloc.addend)), |
| 846 | ), | 1722 | ), |
| ... | @@ -848,7 +1724,7 @@ pub const Reloc = extern struct { | ... | @@ -848,7 +1724,7 @@ pub const Reloc = extern struct { |
| 848 | ), | 1724 | ), |
| 849 | .SIZE64 => std.mem.writeInt( | 1725 | .SIZE64 => std.mem.writeInt( |
| 850 | u64, | 1726 | u64, |
| 851 | loc_slice[0..8], | 1727 | dest_slice[0..8], |
| 852 | elf.targetLoad(&target_sym.size) +% @as(u64, @bitCast(reloc.addend)), | 1728 | elf.targetLoad(&target_sym.size) +% @as(u64, @bitCast(reloc.addend)), |
| 853 | target_endian, | 1729 | target_endian, |
| 854 | ), | 1730 | ), |
| ... | @@ -861,9 +1737,9 @@ pub const Reloc = extern struct { | ... | @@ -861,9 +1737,9 @@ pub const Reloc = extern struct { |
| 861 | pub fn delete(reloc: *Reloc, elf: *Elf) void { | 1737 | pub fn delete(reloc: *Reloc, elf: *Elf) void { |
| 862 | switch (reloc.prev) { | 1738 | switch (reloc.prev) { |
| 863 | .none => { | 1739 | .none => { |
| 864 | const target = reloc.target.get(elf); | 1740 | const target_ptr = reloc.target.index(elf).ptr(elf); |
| 865 | assert(target.target_relocs.get(elf) == reloc); | 1741 | assert(target_ptr.first_target_reloc.get(elf) == reloc); |
| 866 | target.target_relocs = reloc.next; | 1742 | target_ptr.first_target_reloc = reloc.next; |
| 867 | }, | 1743 | }, |
| 868 | else => |prev| prev.get(elf).next = reloc.next, | 1744 | else => |prev| prev.get(elf).next = reloc.next, |
| 869 | } | 1745 | } |
| ... | @@ -874,13 +1750,13 @@ pub const Reloc = extern struct { | ... | @@ -874,13 +1750,13 @@ pub const Reloc = extern struct { |
| 874 | switch (elf.ehdrField(.type)) { | 1750 | switch (elf.ehdrField(.type)) { |
| 875 | .NONE, .CORE, _ => unreachable, | 1751 | .NONE, .CORE, _ => unreachable, |
| 876 | .REL => { | 1752 | .REL => { |
| 877 | const sh = reloc.loc.shndx(elf).get(elf); | 1753 | const sh = elf.getNodeShndx(reloc.node).get(elf); |
| 878 | switch (elf.shdrPtr(sh.rela_si.shndx(elf))) { | 1754 | switch (elf.shdrPtr(sh.rela_shndx)) { |
| 879 | inline else => |shdr, class| { | 1755 | inline else => |shdr, class| { |
| 880 | const Rela = class.ElfN().Rela; | 1756 | const Rela = class.ElfN().Rela; |
| 881 | const ent_size = elf.targetLoad(&shdr.entsize); | 1757 | const ent_size = elf.targetLoad(&shdr.entsize); |
| 882 | const start = ent_size * reloc.index.unwrap().?; | 1758 | const start = ent_size * reloc.index.unwrap().?; |
| 883 | const rela_slice = sh.rela_si.node(elf).slice(&elf.mf); | 1759 | const rela_slice = sh.rela_shndx.get(elf).ni.slice(&elf.mf); |
| 884 | const rela: *Rela = @ptrCast(@alignCast( | 1760 | const rela: *Rela = @ptrCast(@alignCast( |
| 885 | rela_slice[@intCast(start)..][0..@intCast(ent_size)], | 1761 | rela_slice[@intCast(start)..][0..@intCast(ent_size)], |
| 886 | )); | 1762 | )); |
| ... | @@ -901,6 +1777,38 @@ pub const Reloc = extern struct { | ... | @@ -901,6 +1777,38 @@ pub const Reloc = extern struct { |
| 901 | reloc.* = undefined; | 1777 | reloc.* = undefined; |
| 902 | } | 1778 | } |
| 903 | | 1779 | |
| | 1780 | fn updateTargetIndex(reloc: *const Reloc, elf: *Elf) void { |
| | 1781 | assert(elf.ehdrField(.type) == .REL); |
| | 1782 | const sh = elf.getNodeShndx(reloc.node).get(elf); |
| | 1783 | switch (elf.shdrPtr(sh.rela_shndx)) { |
| | 1784 | inline else => |shdr, class| { |
| | 1785 | assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela)); |
| | 1786 | const size = elf.targetLoad(&shdr.size); |
| | 1787 | const raw_rela_slice = sh.rela_shndx.get(elf).ni.slice(&elf.mf); |
| | 1788 | const rela_slice: []class.ElfN().Rela = @ptrCast(@alignCast(raw_rela_slice[0..@intCast(size)])); |
| | 1789 | elf.targetStore(&rela_slice[reloc.index.unwrap().?].info, .{ |
| | 1790 | .type = @intCast(reloc.type.unwrap(elf)), |
| | 1791 | .sym = @intCast(@intFromEnum(reloc.target.index(elf))), |
| | 1792 | }); |
| | 1793 | }, |
| | 1794 | } |
| | 1795 | } |
| | 1796 | |
| | 1797 | fn updateNodeOffset(reloc: *const Reloc, elf: *Elf, node_offset: u64) void { |
| | 1798 | assert(elf.ehdrField(.type) == .REL); |
| | 1799 | const total_offset = node_offset + reloc.offset; |
| | 1800 | const sh = elf.getNodeShndx(reloc.node).get(elf); |
| | 1801 | switch (elf.shdrPtr(sh.rela_shndx)) { |
| | 1802 | inline else => |shdr, class| { |
| | 1803 | assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela)); |
| | 1804 | const size = elf.targetLoad(&shdr.size); |
| | 1805 | const raw_rela_slice = sh.rela_shndx.get(elf).ni.slice(&elf.mf); |
| | 1806 | const rela_slice: []class.ElfN().Rela = @ptrCast(@alignCast(raw_rela_slice[0..@intCast(size)])); |
| | 1807 | elf.targetStore(&rela_slice[reloc.index.unwrap().?].offset, @intCast(total_offset)); |
| | 1808 | }, |
| | 1809 | } |
| | 1810 | } |
| | 1811 | |
| 904 | comptime { | 1812 | comptime { |
| 905 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Reloc) == 40); | 1813 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Reloc) == 40); |
| 906 | } | 1814 | } |
| ... | @@ -1001,34 +1909,38 @@ fn create( | ... | @@ -1001,34 +1909,38 @@ fn create( |
| 1001 | .nodes = .empty, | 1909 | .nodes = .empty, |
| 1002 | .shdrs = .empty, | 1910 | .shdrs = .empty, |
| 1003 | .phdrs = .empty, | 1911 | .phdrs = .empty, |
| 1004 | .si = .{ | 1912 | .shndx = .{ |
| 1005 | .dynsym = .null, | 1913 | .got = .UNDEF, |
| 1006 | .dynstr = .null, | 1914 | .got_plt = .UNDEF, |
| 1007 | .dynamic = .null, | 1915 | .plt = .UNDEF, |
| 1008 | .tdata = .null, | 1916 | .plt_sec = .UNDEF, |
| 1009 | .entry = .null, | 1917 | .dynsym = .UNDEF, |
| | 1918 | .dynstr = .UNDEF, |
| | 1919 | .dynamic = .UNDEF, |
| | 1920 | .tdata = .UNDEF, |
| 1010 | }, | 1921 | }, |
| 1011 | .symtab = .empty, | 1922 | .symtab = .empty, |
| 1012 | .shstrtab = .{ | 1923 | .globals = .{ |
| 1013 | .map = .empty, | 1924 | .strong_def = .empty, |
| 1014 | }, | 1925 | .weak_def = .empty, |
| 1015 | .strtab = .{ | 1926 | .strong_undef = .empty, |
| 1016 | .map = .empty, | 1927 | .weak_undef = .empty, |
| 1017 | }, | | |
| 1018 | .dynsym = .empty, | | |
| 1019 | .dynstr = .{ | | |
| 1020 | .map = .empty, | | |
| 1021 | }, | 1928 | }, |
| | 1929 | .node_global_symbols = .empty, |
| | 1930 | .shstrtab = .{ .map = .empty }, |
| | 1931 | .strtab = .{ .map = .empty }, |
| | 1932 | .dynstr = .{ .map = .empty }, |
| 1022 | .got = .{ | 1933 | .got = .{ |
| 1023 | .len = 0, | 1934 | .len = 0, |
| 1024 | .tlsld = .none, | 1935 | .tlsld = .none, |
| 1025 | .plt = .empty, | 1936 | .plt = .empty, |
| 1026 | }, | 1937 | }, |
| | 1938 | .first_plt_reloc = .none, |
| | 1939 | .first_dynamic_reloc = .none, |
| 1027 | .needed = .empty, | 1940 | .needed = .empty, |
| 1028 | .inputs = .empty, | 1941 | .inputs = .empty, |
| 1029 | .input_sections = .empty, | 1942 | .input_sections = .empty, |
| 1030 | .input_section_pending_index = 0, | 1943 | .input_section_pending_index = 0, |
| 1031 | .globals = .empty, | | |
| 1032 | .navs = .empty, | 1944 | .navs = .empty, |
| 1033 | .uavs = .empty, | 1945 | .uavs = .empty, |
| 1034 | .lazy = comptime .initFill(.{ | 1946 | .lazy = comptime .initFill(.{ |
| ... | @@ -1037,6 +1949,7 @@ fn create( | ... | @@ -1037,6 +1949,7 @@ fn create( |
| 1037 | }), | 1949 | }), |
| 1038 | .pending_uavs = .empty, | 1950 | .pending_uavs = .empty, |
| 1039 | .relocs = .empty, | 1951 | .relocs = .empty, |
| | 1952 | .changed_symtab_index = .empty, |
| 1040 | .const_prog_node = .none, | 1953 | .const_prog_node = .none, |
| 1041 | .synth_prog_node = .none, | 1954 | .synth_prog_node = .none, |
| 1042 | .input_prog_node = .none, | 1955 | .input_prog_node = .none, |
| ... | @@ -1054,21 +1967,25 @@ pub fn deinit(elf: *Elf) void { | ... | @@ -1054,21 +1967,25 @@ pub fn deinit(elf: *Elf) void { |
| 1054 | elf.shdrs.deinit(gpa); | 1967 | elf.shdrs.deinit(gpa); |
| 1055 | elf.phdrs.deinit(gpa); | 1968 | elf.phdrs.deinit(gpa); |
| 1056 | elf.symtab.deinit(gpa); | 1969 | elf.symtab.deinit(gpa); |
| | 1970 | elf.globals.strong_def.deinit(gpa); |
| | 1971 | elf.globals.weak_def.deinit(gpa); |
| | 1972 | elf.globals.strong_undef.deinit(gpa); |
| | 1973 | elf.globals.weak_undef.deinit(gpa); |
| | 1974 | elf.node_global_symbols.deinit(gpa); |
| 1057 | elf.shstrtab.map.deinit(gpa); | 1975 | elf.shstrtab.map.deinit(gpa); |
| 1058 | elf.strtab.map.deinit(gpa); | 1976 | elf.strtab.map.deinit(gpa); |
| 1059 | elf.dynsym.deinit(gpa); | | |
| 1060 | elf.dynstr.map.deinit(gpa); | 1977 | elf.dynstr.map.deinit(gpa); |
| 1061 | elf.got.plt.deinit(gpa); | 1978 | elf.got.plt.deinit(gpa); |
| 1062 | elf.needed.deinit(gpa); | 1979 | elf.needed.deinit(gpa); |
| 1063 | for (elf.inputs.items) |input| if (input.member) |m| gpa.free(m); | 1980 | for (elf.inputs.items) |input| if (input.member) |m| gpa.free(m); |
| 1064 | elf.inputs.deinit(gpa); | 1981 | elf.inputs.deinit(gpa); |
| 1065 | elf.input_sections.deinit(gpa); | 1982 | elf.input_sections.deinit(gpa); |
| 1066 | elf.globals.deinit(gpa); | | |
| 1067 | elf.navs.deinit(gpa); | 1983 | elf.navs.deinit(gpa); |
| 1068 | elf.uavs.deinit(gpa); | 1984 | elf.uavs.deinit(gpa); |
| 1069 | for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa); | 1985 | for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa); |
| 1070 | elf.pending_uavs.deinit(gpa); | 1986 | elf.pending_uavs.deinit(gpa); |
| 1071 | elf.relocs.deinit(gpa); | 1987 | elf.relocs.deinit(gpa); |
| | 1988 | elf.changed_symtab_index.deinit(gpa); |
| 1072 | elf.* = undefined; | 1989 | elf.* = undefined; |
| 1073 | } | 1990 | } |
| 1074 | | 1991 | |
| ... | @@ -1123,19 +2040,18 @@ fn initHeaders( | ... | @@ -1123,19 +2040,18 @@ fn initHeaders( |
| 1123 | const expected_nodes_len = expected_nodes_len: switch (@"type") { | 2040 | const expected_nodes_len = expected_nodes_len: switch (@"type") { |
| 1124 | .NONE, .CORE, _ => unreachable, | 2041 | .NONE, .CORE, _ => unreachable, |
| 1125 | .REL => { | 2042 | .REL => { |
| | 2043 | // Each phdr is actually going to be an shdr. |
| 1126 | defer phnum = 0; | 2044 | defer phnum = 0; |
| 1127 | break :expected_nodes_len 5 + phnum; | 2045 | break :expected_nodes_len 5 + phnum; |
| 1128 | }, | 2046 | }, |
| 1129 | .EXEC, .DYN => break :expected_nodes_len 8 + phnum * 2 + | 2047 | .EXEC, .DYN => break :expected_nodes_len 10 + |
| 1130 | @intFromBool(maybe_interp != null) + | 2048 | phnum * 2 - 1 + // each phdr also has a matching shdr, except for the PT_PHDR phdr |
| 1131 | @as(usize, 4) * @intFromBool(have_dynamic_section) + | 2049 | @as(usize, 4) * @intFromBool(have_dynamic_section), // .dynstr, .dynsym, .rela.dyn, .rela.plt |
| 1132 | @intFromBool(comp.config.any_non_single_threaded), | | |
| 1133 | }; | 2050 | }; |
| 1134 | try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len); | 2051 | try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len); |
| 1135 | try elf.shdrs.ensureTotalCapacity(gpa, shnum); | 2052 | try elf.shdrs.ensureTotalCapacity(gpa, shnum); |
| 1136 | try elf.phdrs.resize(gpa, phnum); | 2053 | try elf.phdrs.resize(gpa, phnum); |
| 1137 | try elf.symtab.ensureTotalCapacity(gpa, 1); | 2054 | try elf.symtab.ensureTotalCapacity(gpa, 1); |
| 1138 | if (have_dynamic_section) try elf.dynsym.ensureTotalCapacity(gpa, 1); | | |
| 1139 | elf.nodes.appendAssumeCapacity(.file); | 2055 | elf.nodes.appendAssumeCapacity(.file); |
| 1140 | | 2056 | |
| 1141 | switch (class) { | 2057 | switch (class) { |
| ... | @@ -1150,14 +2066,13 @@ fn initHeaders( | ... | @@ -1150,14 +2066,13 @@ fn initHeaders( |
| 1150 | elf.nodes.appendAssumeCapacity(.ehdr); | 2066 | elf.nodes.appendAssumeCapacity(.ehdr); |
| 1151 | | 2067 | |
| 1152 | const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(elf.ni.ehdr.slice(&elf.mf))); | 2068 | const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(elf.ni.ehdr.slice(&elf.mf))); |
| 1153 | const EI = std.elf.EI; | 2069 | ehdr.ident = .{ |
| 1154 | @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC); | 2070 | .class = class, |
| 1155 | ehdr.ident[EI.CLASS] = @intFromEnum(class); | 2071 | .data = data, |
| 1156 | ehdr.ident[EI.DATA] = @intFromEnum(data); | 2072 | .version = 1, |
| 1157 | ehdr.ident[EI.VERSION] = 1; | 2073 | .osabi = osabi, |
| 1158 | ehdr.ident[EI.OSABI] = @intFromEnum(osabi); | 2074 | .abiversion = 0, |
| 1159 | ehdr.ident[EI.ABIVERSION] = 0; | 2075 | }; |
| 1160 | @memset(ehdr.ident[EI.PAD..], 0); | | |
| 1161 | ehdr.type = @"type"; | 2076 | ehdr.type = @"type"; |
| 1162 | ehdr.machine = machine; | 2077 | ehdr.machine = machine; |
| 1163 | ehdr.version = 1; | 2078 | ehdr.version = 1; |
| ... | @@ -1176,7 +2091,7 @@ fn initHeaders( | ... | @@ -1176,7 +2091,7 @@ fn initHeaders( |
| 1176 | } | 2091 | } |
| 1177 | | 2092 | |
| 1178 | assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{ | 2093 | assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{ |
| 1179 | .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum), | 2094 | .size = @as(u64, elf.ehdrField(.shentsize)) * @as(u64, elf.ehdrField(.shnum)), |
| 1180 | .alignment = elf.mf.flags.block_size, | 2095 | .alignment = elf.mf.flags.block_size, |
| 1181 | .moved = true, | 2096 | .moved = true, |
| 1182 | .resized = true, | 2097 | .resized = true, |
| ... | @@ -1366,7 +2281,7 @@ fn initHeaders( | ... | @@ -1366,7 +2281,7 @@ fn initHeaders( |
| 1366 | | 2281 | |
| 1367 | const sh_undef: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf))); | 2282 | const sh_undef: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf))); |
| 1368 | sh_undef.* = .{ | 2283 | sh_undef.* = .{ |
| 1369 | .name = try elf.string(.shstrtab, ""), | 2284 | .name = @intFromEnum(String(.shstrtab).empty), |
| 1370 | .type = .NULL, | 2285 | .type = .NULL, |
| 1371 | .flags = .{ .shf = .{} }, | 2286 | .flags = .{ .shf = .{} }, |
| 1372 | .addr = 0, | 2287 | .addr = 0, |
| ... | @@ -1378,24 +2293,23 @@ fn initHeaders( | ... | @@ -1378,24 +2293,23 @@ fn initHeaders( |
| 1378 | .entsize = 0, | 2293 | .entsize = 0, |
| 1379 | }; | 2294 | }; |
| 1380 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef); | 2295 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef); |
| 1381 | elf.shdrs.appendAssumeCapacity(.{ .si = .null, .rela_si = .null, .rela_free = .none }); | 2296 | elf.shdrs.appendAssumeCapacity(.{ .lsi = .null, .ni = .none, .rela_shndx = .UNDEF, .rela_free = .none }); |
| 1382 | | 2297 | |
| 1383 | elf.symtab.addOneAssumeCapacity().* = .{ | 2298 | elf.symtab.addOneAssumeCapacity().* = .{ |
| 1384 | .ni = .none, | 2299 | .node = .none, |
| 1385 | .loc_relocs = .none, | 2300 | .first_target_reloc = .none, |
| 1386 | .target_relocs = .none, | | |
| 1387 | .unused = 0, | | |
| 1388 | }; | 2301 | }; |
| 1389 | assert(elf.si.symtab == try elf.addSection(elf.ni.file, .{ | 2302 | assert(.symtab == try elf.addSection(elf.ni.file, .{ |
| 1390 | .type = .SYMTAB, | 2303 | .type = .SYMTAB, |
| 1391 | .size = @sizeOf(ElfN.Sym) * 1, | 2304 | .size = @sizeOf(ElfN.Sym) * 1, |
| 1392 | .addralign = addr_align, | 2305 | .addralign = addr_align, |
| 1393 | .entsize = @sizeOf(ElfN.Sym), | 2306 | .entsize = @sizeOf(ElfN.Sym), |
| 1394 | .node_align = elf.mf.flags.block_size, | 2307 | .node_align = elf.mf.flags.block_size, |
| | 2308 | .info = 1, // index of first non-local symbol |
| 1395 | })); | 2309 | })); |
| 1396 | const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class)); | 2310 | const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class)); |
| 1397 | symtab_null.* = .{ | 2311 | symtab_null.* = .{ |
| 1398 | .name = try elf.string(.strtab, ""), | 2312 | .name = @intFromEnum(String(.strtab).empty), |
| 1399 | .value = 0, | 2313 | .value = 0, |
| 1400 | .size = 0, | 2314 | .size = 0, |
| 1401 | .info = .{ .type = .NOTYPE, .bind = .LOCAL }, | 2315 | .info = .{ .type = .NOTYPE, .bind = .LOCAL }, |
| ... | @@ -1408,55 +2322,56 @@ fn initHeaders( | ... | @@ -1408,55 +2322,56 @@ fn initHeaders( |
| 1408 | ehdr.shstrndx = ehdr.shnum; | 2322 | ehdr.shstrndx = ehdr.shnum; |
| 1409 | }, | 2323 | }, |
| 1410 | } | 2324 | } |
| 1411 | assert(elf.si.shstrtab == try elf.addSection(elf.ni.file, .{ | 2325 | assert(.shstrtab == try elf.addSection(elf.ni.file, .{ |
| 1412 | .type = .STRTAB, | 2326 | .type = .STRTAB, |
| 1413 | .size = 1, | 2327 | .size = 1, |
| 1414 | .entsize = 1, | 2328 | .entsize = 1, |
| 1415 | .node_align = elf.mf.flags.block_size, | 2329 | .node_align = elf.mf.flags.block_size, |
| 1416 | })); | 2330 | })); |
| 1417 | try elf.renameSection(.symtab, ".symtab"); | 2331 | Section.Index.get(.shstrtab, elf).ni.slice(&elf.mf)[0] = 0; |
| 1418 | try elf.renameSection(.shstrtab, ".shstrtab"); | | |
| 1419 | elf.si.shstrtab.node(elf).slice(&elf.mf)[0] = 0; | | |
| 1420 | | 2332 | |
| 1421 | assert(elf.si.strtab == try elf.addSection(elf.ni.file, .{ | 2333 | try Section.Index.symtab.rename(elf, ".symtab"); |
| | 2334 | try Section.Index.shstrtab.rename(elf, ".shstrtab"); |
| | 2335 | |
| | 2336 | assert(.strtab == try elf.addSection(elf.ni.file, .{ |
| 1422 | .name = ".strtab", | 2337 | .name = ".strtab", |
| 1423 | .type = .STRTAB, | 2338 | .type = .STRTAB, |
| 1424 | .size = 1, | 2339 | .size = 1, |
| 1425 | .entsize = 1, | 2340 | .entsize = 1, |
| 1426 | .node_align = elf.mf.flags.block_size, | 2341 | .node_align = elf.mf.flags.block_size, |
| 1427 | })); | 2342 | })); |
| 1428 | switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) { | 2343 | Section.Index.get(.strtab, elf).ni.slice(&elf.mf)[0] = 0; |
| 1429 | inline else => |shdr| elf.targetStore(&shdr.link, @intFromEnum(elf.si.strtab.shndx(elf))), | 2344 | switch (elf.shdrPtr(.symtab)) { |
| | 2345 | inline else => |shdr| elf.targetStore(&shdr.link, @intFromEnum(Section.Index.strtab)), |
| 1430 | } | 2346 | } |
| 1431 | elf.si.strtab.node(elf).slice(&elf.mf)[0] = 0; | | |
| 1432 | | 2347 | |
| 1433 | assert(elf.si.rodata == try elf.addSection(elf.ni.rodata, .{ | 2348 | assert(.rodata == try elf.addSection(elf.ni.rodata, .{ |
| 1434 | .name = ".rodata", | 2349 | .name = ".rodata", |
| 1435 | .flags = .{ .ALLOC = true }, | 2350 | .flags = .{ .ALLOC = true }, |
| 1436 | .addralign = elf.mf.flags.block_size, | 2351 | .addralign = elf.mf.flags.block_size, |
| 1437 | })); | 2352 | })); |
| 1438 | assert(elf.si.text == try elf.addSection(elf.ni.text, .{ | 2353 | assert(.text == try elf.addSection(elf.ni.text, .{ |
| 1439 | .name = ".text", | 2354 | .name = ".text", |
| 1440 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, | 2355 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, |
| 1441 | .addralign = elf.mf.flags.block_size, | 2356 | .addralign = elf.mf.flags.block_size, |
| 1442 | })); | 2357 | })); |
| 1443 | assert(elf.si.data == try elf.addSection(elf.ni.data, .{ | 2358 | assert(.data == try elf.addSection(elf.ni.data, .{ |
| 1444 | .name = ".data", | 2359 | .name = ".data", |
| 1445 | .flags = .{ .WRITE = true, .ALLOC = true }, | 2360 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 1446 | .addralign = elf.mf.flags.block_size, | 2361 | .addralign = elf.mf.flags.block_size, |
| 1447 | })); | 2362 | })); |
| 1448 | assert(elf.si.data_rel_ro == try elf.addSection(elf.ni.data_rel_ro, .{ | 2363 | assert(.data_rel_ro == try elf.addSection(elf.ni.data_rel_ro, .{ |
| 1449 | .name = ".data.rel.ro", | 2364 | .name = ".data.rel.ro", |
| 1450 | .flags = .{ .WRITE = true, .ALLOC = true }, | 2365 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 1451 | .addralign = elf.mf.flags.block_size, | 2366 | .addralign = elf.mf.flags.block_size, |
| 1452 | })); | 2367 | })); |
| 1453 | if (@"type" != .REL) { | 2368 | if (@"type" != .REL) { |
| 1454 | assert(elf.si.got == try elf.addSection(elf.ni.data_rel_ro, .{ | 2369 | elf.shndx.got = try elf.addSection(elf.ni.data_rel_ro, .{ |
| 1455 | .name = ".got", | 2370 | .name = ".got", |
| 1456 | .flags = .{ .WRITE = true, .ALLOC = true }, | 2371 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 1457 | .addralign = addr_align, | 2372 | .addralign = addr_align, |
| 1458 | })); | 2373 | }); |
| 1459 | assert(elf.si.got_plt == try elf.addSection( | 2374 | elf.shndx.got_plt = try elf.addSection( |
| 1460 | if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data, | 2375 | if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data, |
| 1461 | .{ | 2376 | .{ |
| 1462 | .name = ".got.plt", | 2377 | .name = ".got.plt", |
| ... | @@ -1469,26 +2384,26 @@ fn initHeaders( | ... | @@ -1469,26 +2384,26 @@ fn initHeaders( |
| 1469 | }, | 2384 | }, |
| 1470 | .addralign = addr_align, | 2385 | .addralign = addr_align, |
| 1471 | }, | 2386 | }, |
| 1472 | )); | 2387 | ); |
| 1473 | const plt_size: std.elf.Xword, const plt_align: std.mem.Alignment, const plt_sec = | 2388 | const plt_size: std.elf.Xword, const plt_align: std.mem.Alignment, const plt_sec = |
| 1474 | switch (machine) { | 2389 | switch (machine) { |
| 1475 | else => @panic(@tagName(machine)), | 2390 | else => @panic(@tagName(machine)), |
| 1476 | .X86_64 => .{ 16, .@"16", true }, | 2391 | .X86_64 => .{ 16, .@"16", true }, |
| 1477 | }; | 2392 | }; |
| 1478 | assert(elf.si.plt == try elf.addSection(elf.ni.text, .{ | 2393 | elf.shndx.plt = try elf.addSection(elf.ni.text, .{ |
| 1479 | .name = ".plt", | 2394 | .name = ".plt", |
| 1480 | .type = .PROGBITS, | 2395 | .type = .PROGBITS, |
| 1481 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, | 2396 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, |
| 1482 | .size = plt_size, | 2397 | .size = plt_size, |
| 1483 | .addralign = plt_align, | 2398 | .addralign = plt_align, |
| 1484 | .node_align = elf.mf.flags.block_size, | 2399 | .node_align = elf.mf.flags.block_size, |
| 1485 | })); | 2400 | }); |
| 1486 | if (plt_sec) assert(elf.si.plt_sec == try elf.addSection(elf.ni.text, .{ | 2401 | if (plt_sec) elf.shndx.plt_sec = try elf.addSection(elf.ni.text, .{ |
| 1487 | .name = ".plt.sec", | 2402 | .name = ".plt.sec", |
| 1488 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, | 2403 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, |
| 1489 | .addralign = plt_align, | 2404 | .addralign = plt_align, |
| 1490 | .node_align = elf.mf.flags.block_size, | 2405 | .node_align = elf.mf.flags.block_size, |
| 1491 | })); | 2406 | }); |
| 1492 | if (maybe_interp) |interp| { | 2407 | if (maybe_interp) |interp| { |
| 1493 | const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{ | 2408 | const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{ |
| 1494 | .size = interp.len + 1, | 2409 | .size = interp.len + 1, |
| ... | @@ -1499,13 +2414,13 @@ fn initHeaders( | ... | @@ -1499,13 +2414,13 @@ fn initHeaders( |
| 1499 | elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx }); | 2414 | elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx }); |
| 1500 | elf.phdrs.items[interp_phndx] = interp_ni; | 2415 | elf.phdrs.items[interp_phndx] = interp_ni; |
| 1501 | | 2416 | |
| 1502 | const sec_interp_si = try elf.addSection(interp_ni, .{ | 2417 | const sec_interp_shndx = try elf.addSection(interp_ni, .{ |
| 1503 | .name = ".interp", | 2418 | .name = ".interp", |
| 1504 | .type = .PROGBITS, | 2419 | .type = .PROGBITS, |
| 1505 | .flags = .{ .ALLOC = true }, | 2420 | .flags = .{ .ALLOC = true }, |
| 1506 | .size = @intCast(interp.len + 1), | 2421 | .size = @intCast(interp.len + 1), |
| 1507 | }); | 2422 | }); |
| 1508 | const sec_interp = sec_interp_si.node(elf).slice(&elf.mf); | 2423 | const sec_interp = sec_interp_shndx.get(elf).ni.slice(&elf.mf); |
| 1509 | @memcpy(sec_interp[0..interp.len], interp); | 2424 | @memcpy(sec_interp[0..interp.len], interp); |
| 1510 | sec_interp[interp.len] = 0; | 2425 | sec_interp[interp.len] = 0; |
| 1511 | } | 2426 | } |
| ... | @@ -1518,7 +2433,7 @@ fn initHeaders( | ... | @@ -1518,7 +2433,7 @@ fn initHeaders( |
| 1518 | elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx }); | 2433 | elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx }); |
| 1519 | elf.phdrs.items[dynamic_phndx] = dynamic_ni; | 2434 | elf.phdrs.items[dynamic_phndx] = dynamic_ni; |
| 1520 | | 2435 | |
| 1521 | elf.si.dynstr = try elf.addSection(elf.ni.rodata, .{ | 2436 | const dynstr_shndx = try elf.addSection(elf.ni.rodata, .{ |
| 1522 | .name = ".dynstr", | 2437 | .name = ".dynstr", |
| 1523 | .type = .STRTAB, | 2438 | .type = .STRTAB, |
| 1524 | .flags = .{ .ALLOC = true }, | 2439 | .flags = .{ .ALLOC = true }, |
| ... | @@ -1526,26 +2441,27 @@ fn initHeaders( | ... | @@ -1526,26 +2441,27 @@ fn initHeaders( |
| 1526 | .entsize = 1, | 2441 | .entsize = 1, |
| 1527 | .node_align = elf.mf.flags.block_size, | 2442 | .node_align = elf.mf.flags.block_size, |
| 1528 | }); | 2443 | }); |
| 1529 | const dynstr_shndx = elf.si.dynstr.shndx(elf); | 2444 | dynstr_shndx.get(elf).ni.slice(&elf.mf)[0] = 0; |
| 1530 | elf.dynsym.putAssumeCapacityNoClobber(.null, {}); | 2445 | elf.shndx.dynstr = dynstr_shndx; |
| | 2446 | |
| 1531 | switch (class) { | 2447 | switch (class) { |
| 1532 | .NONE, _ => unreachable, | 2448 | .NONE, _ => unreachable, |
| 1533 | inline else => |ct_class| { | 2449 | inline else => |ct_class| { |
| 1534 | const Sym = ct_class.ElfN().Sym; | 2450 | const Sym = ct_class.ElfN().Sym; |
| 1535 | elf.si.dynsym = try elf.addSection(elf.ni.rodata, .{ | 2451 | elf.shndx.dynsym = try elf.addSection(elf.ni.rodata, .{ |
| 1536 | .name = ".dynsym", | 2452 | .name = ".dynsym", |
| 1537 | .type = .DYNSYM, | 2453 | .type = .DYNSYM, |
| 1538 | .flags = .{ .ALLOC = true }, | 2454 | .flags = .{ .ALLOC = true }, |
| 1539 | .size = @sizeOf(Sym) * 1, | 2455 | .size = @sizeOf(Sym) * 1, |
| 1540 | .link = @intFromEnum(dynstr_shndx), | 2456 | .link = dynstr_shndx.toSection().?, |
| 1541 | .info = 1, | 2457 | .info = 1, |
| 1542 | .addralign = addr_align, | 2458 | .addralign = addr_align, |
| 1543 | .entsize = @sizeOf(Sym), | 2459 | .entsize = @sizeOf(Sym), |
| 1544 | .node_align = elf.mf.flags.block_size, | 2460 | .node_align = elf.mf.flags.block_size, |
| 1545 | }); | 2461 | }); |
| 1546 | const dynsym_null = &@field(elf.dynsymSlice(), @tagName(ct_class))[0]; | 2462 | const dynsym_null = @field(elf.dynsymPtr(0), @tagName(ct_class)); |
| 1547 | dynsym_null.* = .{ | 2463 | dynsym_null.* = .{ |
| 1548 | .name = try elf.string(.dynstr, ""), | 2464 | .name = @intFromEnum(String(.dynstr).empty), |
| 1549 | .value = 0, | 2465 | .value = 0, |
| 1550 | .size = 0, | 2466 | .size = 0, |
| 1551 | .info = .{ .type = .NOTYPE, .bind = .LOCAL }, | 2467 | .info = .{ .type = .NOTYPE, .bind = .LOCAL }, |
| ... | @@ -1562,57 +2478,57 @@ fn initHeaders( | ... | @@ -1562,57 +2478,57 @@ fn initHeaders( |
| 1562 | .NONE, _ => unreachable, | 2478 | .NONE, _ => unreachable, |
| 1563 | inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela), | 2479 | inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela), |
| 1564 | }; | 2480 | }; |
| 1565 | elf.si.got.shndx(elf).get(elf).rela_si = try elf.addSection(elf.ni.rodata, .{ | 2481 | elf.shndx.got.get(elf).rela_shndx = try elf.addSection(elf.ni.rodata, .{ |
| 1566 | .name = ".rela.dyn", | 2482 | .name = ".rela.dyn", |
| 1567 | .type = .RELA, | 2483 | .type = .RELA, |
| 1568 | .flags = .{ .ALLOC = true }, | 2484 | .flags = .{ .ALLOC = true }, |
| 1569 | .link = @intFromEnum(elf.si.dynsym.shndx(elf)), | 2485 | .link = elf.shndx.dynsym.toSection().?, |
| 1570 | .addralign = addr_align, | 2486 | .addralign = addr_align, |
| 1571 | .entsize = rela_size, | 2487 | .entsize = rela_size, |
| 1572 | .node_align = elf.mf.flags.block_size, | 2488 | .node_align = elf.mf.flags.block_size, |
| 1573 | }); | 2489 | }); |
| 1574 | const got_plt_shndx = elf.si.got_plt.shndx(elf); | 2490 | const got_plt_shndx = elf.shndx.got_plt; |
| 1575 | got_plt_shndx.get(elf).rela_si = try elf.addSection(elf.ni.rodata, .{ | 2491 | got_plt_shndx.get(elf).rela_shndx = try elf.addSection(elf.ni.rodata, .{ |
| 1576 | .name = ".rela.plt", | 2492 | .name = ".rela.plt", |
| 1577 | .type = .RELA, | 2493 | .type = .RELA, |
| 1578 | .flags = .{ .ALLOC = true, .INFO_LINK = true }, | 2494 | .flags = .{ .ALLOC = true, .INFO_LINK = true }, |
| 1579 | .link = @intFromEnum(elf.si.dynsym.shndx(elf)), | 2495 | .link = elf.shndx.dynsym.toSection().?, |
| 1580 | .info = @intFromEnum(got_plt_shndx), | 2496 | .info = got_plt_shndx.toSection().?, |
| 1581 | .addralign = addr_align, | 2497 | .addralign = addr_align, |
| 1582 | .entsize = rela_size, | 2498 | .entsize = rela_size, |
| 1583 | .node_align = elf.mf.flags.block_size, | 2499 | .node_align = elf.mf.flags.block_size, |
| 1584 | }); | 2500 | }); |
| 1585 | elf.si.dynamic = try elf.addSection(dynamic_ni, .{ | 2501 | elf.shndx.dynamic = try elf.addSection(dynamic_ni, .{ |
| 1586 | .name = ".dynamic", | 2502 | .name = ".dynamic", |
| 1587 | .type = .DYNAMIC, | 2503 | .type = .DYNAMIC, |
| 1588 | .flags = .{ .ALLOC = true, .WRITE = true }, | 2504 | .flags = .{ .ALLOC = true, .WRITE = true }, |
| 1589 | .link = @intFromEnum(dynstr_shndx), | 2505 | .link = dynstr_shndx.toSection().?, |
| 1590 | .entsize = @intCast(addr_align.toByteUnits() * 2), | 2506 | .entsize = @intCast(addr_align.toByteUnits() * 2), |
| 1591 | .node_align = addr_align, | 2507 | .node_align = addr_align, |
| 1592 | }); | 2508 | }); |
| 1593 | switch (machine) { | 2509 | switch (machine) { |
| 1594 | else => @panic(@tagName(machine)), | 2510 | else => @panic(@tagName(machine)), |
| 1595 | .X86_64 => { | 2511 | .X86_64 => { |
| 1596 | @memcpy(elf.si.plt.node(elf).slice(&elf.mf)[0..16], &[16]u8{ | 2512 | const plt_ni = elf.shndx.plt.get(elf).ni; |
| | 2513 | const got_plt_sym: Symbol.Id = .local(elf.shndx.got_plt.get(elf).lsi); |
| | 2514 | @memcpy(plt_ni.slice(&elf.mf)[0..16], &[16]u8{ |
| 1597 | 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // push 0x0(%rip) | 2515 | 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // push 0x0(%rip) |
| 1598 | 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0(%rip) | 2516 | 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0(%rip) |
| 1599 | 0x0f, 0x1f, 0x40, 0x00, // nopl 0x0(%rax) | 2517 | 0x0f, 0x1f, 0x40, 0x00, // nopl 0x0(%rax) |
| 1600 | }); | 2518 | }); |
| 1601 | const plt_sym = elf.si.plt.get(elf); | 2519 | elf.first_plt_reloc = @enumFromInt(elf.relocs.items.len); |
| 1602 | assert(plt_sym.loc_relocs == .none); | 2520 | try elf.ensureUnusedRelocCapacity(plt_ni, 2); |
| 1603 | plt_sym.loc_relocs = @enumFromInt(elf.relocs.items.len); | | |
| 1604 | try elf.ensureUnusedRelocCapacity(elf.si.plt, 2); | | |
| 1605 | elf.addRelocAssumeCapacity( | 2521 | elf.addRelocAssumeCapacity( |
| 1606 | elf.si.plt, | 2522 | plt_ni, |
| 1607 | 2, | 2523 | 2, |
| 1608 | elf.si.got_plt, | 2524 | got_plt_sym, |
| 1609 | 8 * 1 - 4, | 2525 | 8 * 1 - 4, |
| 1610 | .{ .X86_64 = .PC32 }, | 2526 | .{ .X86_64 = .PC32 }, |
| 1611 | ); | 2527 | ); |
| 1612 | elf.addRelocAssumeCapacity( | 2528 | elf.addRelocAssumeCapacity( |
| 1613 | elf.si.plt, | 2529 | plt_ni, |
| 1614 | 8, | 2530 | 8, |
| 1615 | elf.si.got_plt, | 2531 | got_plt_sym, |
| 1616 | 8 * 2 - 4, | 2532 | 8 * 2 - 4, |
| 1617 | .{ .X86_64 = .PC32 }, | 2533 | .{ .X86_64 = .PC32 }, |
| 1618 | ); | 2534 | ); |
| ... | @@ -1632,7 +2548,7 @@ fn initHeaders( | ... | @@ -1632,7 +2548,7 @@ fn initHeaders( |
| 1632 | assert(maybe_interp == null); | 2548 | assert(maybe_interp == null); |
| 1633 | assert(!have_dynamic_section); | 2549 | assert(!have_dynamic_section); |
| 1634 | } | 2550 | } |
| 1635 | if (comp.config.any_non_single_threaded) elf.si.tdata = try elf.addSection(elf.ni.tls, .{ | 2551 | if (comp.config.any_non_single_threaded) elf.shndx.tdata = try elf.addSection(elf.ni.tls, .{ |
| 1636 | .name = ".tdata", | 2552 | .name = ".tdata", |
| 1637 | .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true }, | 2553 | .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true }, |
| 1638 | .addralign = elf.mf.flags.block_size, | 2554 | .addralign = elf.mf.flags.block_size, |
| ... | @@ -1642,7 +2558,7 @@ fn initHeaders( | ... | @@ -1642,7 +2558,7 @@ fn initHeaders( |
| 1642 | | 2558 | |
| 1643 | pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void { | 2559 | pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void { |
| 1644 | prog_node.increaseEstimatedTotalItems(4); | 2560 | prog_node.increaseEstimatedTotalItems(4); |
| 1645 | elf.const_prog_node = prog_node.start("Constants", elf.pending_uavs.count()); | 2561 | elf.const_prog_node = prog_node.start("Constants", elf.pending_uavs.items.len); |
| 1646 | elf.synth_prog_node = prog_node.start("Synthetics", count: { | 2562 | elf.synth_prog_node = prog_node.start("Synthetics", count: { |
| 1647 | var count: usize = 0; | 2563 | var count: usize = 0; |
| 1648 | for (&elf.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index; | 2564 | for (&elf.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index; |
| ... | @@ -1669,35 +2585,105 @@ pub fn endProgress(elf: *Elf) void { | ... | @@ -1669,35 +2585,105 @@ pub fn endProgress(elf: *Elf) void { |
| 1669 | fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node { | 2585 | fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node { |
| 1670 | return elf.nodes.get(@intFromEnum(ni)); | 2586 | return elf.nodes.get(@intFromEnum(ni)); |
| 1671 | } | 2587 | } |
| | 2588 | /// Asserts that `ni` is a section, input section, NAV, UAV, or lazy code/data. |
| | 2589 | fn getNodeShndx(elf: *Elf, ni: MappedFile.Node.Index) Section.Index { |
| | 2590 | return switch (elf.getNode(ni)) { |
| | 2591 | .file => unreachable, |
| | 2592 | .ehdr => unreachable, |
| | 2593 | .shdr => unreachable, |
| | 2594 | .segment => unreachable, |
| | 2595 | |
| | 2596 | .section => |shndx| shndx, |
| | 2597 | |
| | 2598 | .input_section, |
| | 2599 | .nav, |
| | 2600 | .uav, |
| | 2601 | .lazy_code, |
| | 2602 | .lazy_const_data, |
| | 2603 | => elf.getNode(ni.parent(&elf.mf)).section, |
| | 2604 | }; |
| | 2605 | } |
| 1672 | fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { | 2606 | fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 1673 | const parent_vaddr = parent_vaddr: { | 2607 | const parent_vaddr = switch (elf.getNode(ni.parent(&elf.mf))) { |
| 1674 | const parent_ni = ni.parent(&elf.mf); | 2608 | .file => return 0, |
| 1675 | const parent_si = switch (elf.getNode(parent_ni)) { | 2609 | .ehdr, .shdr => unreachable, |
| 1676 | .file => return 0, | 2610 | .segment => |phndx| switch (elf.phdrSlice()) { |
| 1677 | .ehdr, .shdr => unreachable, | 2611 | inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr), |
| 1678 | .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) { | 2612 | }, |
| 1679 | inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr), | 2613 | .section => |shndx| if (shndx == elf.shndx.tdata) 0 else shndx.vaddr(elf), |
| 1680 | }, | 2614 | .input_section => unreachable, |
| 1681 | .section => |si| si, | 2615 | inline .nav, .uav, .lazy_code, .lazy_const_data => |i| Symbol.Id.local(i.symbol(elf)).value(elf), |
| 1682 | .input_section => unreachable, | | |
| 1683 | inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf), | | |
| 1684 | }; | | |
| 1685 | break :parent_vaddr if (parent_si == elf.si.tdata) 0 else switch (elf.symPtr(parent_si)) { | | |
| 1686 | inline else => |sym| elf.targetLoad(&sym.value), | | |
| 1687 | }; | | |
| 1688 | }; | 2616 | }; |
| 1689 | const offset, _ = ni.location(&elf.mf).resolve(&elf.mf); | 2617 | const offset, _ = ni.location(&elf.mf).resolve(&elf.mf); |
| 1690 | return parent_vaddr + offset; | 2618 | return parent_vaddr + offset; |
| 1691 | } | 2619 | } |
| 1692 | | 2620 | |
| 1693 | pub fn identClass(elf: *const Elf) std.elf.CLASS { | 2621 | /// Deletes any existing relocations in the given node, and marks the start of the node's contiguous |
| | 2622 | /// sequence of relocations, so that the caller may append the node's updated relocations. |
| | 2623 | /// |
| | 2624 | /// Asserts that `ni` must be a node which supports relocations (see `Elf.Node`). Does not support |
| | 2625 | /// the special-case sections '.plt' and '.dynamic'. |
| | 2626 | fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void { |
| | 2627 | const first_reloc_ptr: *Reloc.Index = switch (elf.getNode(ni)) { |
| | 2628 | .file => unreachable, // cannot contain relocs |
| | 2629 | .ehdr => unreachable, // cannot contain relocs |
| | 2630 | .shdr => unreachable, // cannot contain relocs |
| | 2631 | .segment => unreachable, // cannot contain relocs |
| | 2632 | .section => unreachable, // cannot contain relocs (.plt and .dynamic unsupported) |
| | 2633 | .input_section => |isi| &elf.input_sections.items[@intFromEnum(isi)].first_reloc, |
| | 2634 | .nav => |nmi| &elf.navs.values()[@intFromEnum(nmi)].first_reloc, |
| | 2635 | .uav => |umi| &elf.uavs.values()[@intFromEnum(umi)].first_reloc, |
| | 2636 | inline .lazy_code, .lazy_const_data => |lmi| &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_reloc, |
| | 2637 | }; |
| | 2638 | if (first_reloc_ptr.* != .none) { |
| | 2639 | for (elf.relocs.items[@intFromEnum(first_reloc_ptr.*)..]) |*reloc| { |
| | 2640 | if (reloc.node != ni) break; |
| | 2641 | reloc.delete(elf); |
| | 2642 | } |
| | 2643 | } |
| | 2644 | first_reloc_ptr.* = @enumFromInt(elf.relocs.items.len); |
| | 2645 | } |
| | 2646 | |
| | 2647 | /// Given that `node` has moved, updates all relocations in `node` (starting from `first_reloc`) as |
| | 2648 | /// needed. In relocatables, this means updating the offsets of those relocations. In ELF modules, |
| | 2649 | /// this means applying the relocations. |
| | 2650 | fn flushMovedNodeRelocs( |
| | 2651 | elf: *Elf, |
| | 2652 | node: MappedFile.Node.Index, |
| | 2653 | node_vaddr: u64, |
| | 2654 | first_reloc: Reloc.Index, |
| | 2655 | ) void { |
| | 2656 | if (first_reloc == .none) return; |
| | 2657 | switch (elf.ehdrField(.type)) { |
| | 2658 | .NONE, .CORE, _ => unreachable, |
| | 2659 | .REL => { |
| | 2660 | // In a relocatable, we're not actually applying any relocations ourselves, but we need |
| | 2661 | // to update the offsets of the relocation entries since the node they're in has moved. |
| | 2662 | for (elf.relocs.items[@intFromEnum(first_reloc)..]) |*reloc| { |
| | 2663 | if (reloc.node != node) break; |
| | 2664 | reloc.updateNodeOffset(elf, node_vaddr); |
| | 2665 | } |
| | 2666 | }, |
| | 2667 | .EXEC, .DYN => { |
| | 2668 | // For an ELF module, we just need to apply relocations. |
| | 2669 | for (elf.relocs.items[@intFromEnum(first_reloc)..]) |*reloc| { |
| | 2670 | if (reloc.node != node) break; |
| | 2671 | reloc.apply(elf); |
| | 2672 | } |
| | 2673 | // TODO: once we're emitting runtime relocation entries, we need to update their offsets |
| | 2674 | // too, like the logic for relocatables above. |
| | 2675 | }, |
| | 2676 | } |
| | 2677 | } |
| | 2678 | |
| | 2679 | fn identClass(elf: *const Elf) std.elf.CLASS { |
| 1694 | return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.CLASS]); | 2680 | return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.CLASS]); |
| 1695 | } | 2681 | } |
| 1696 | pub fn identData(elf: *const Elf) std.elf.DATA { | 2682 | fn identData(elf: *const Elf) std.elf.DATA { |
| 1697 | return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.DATA]); | 2683 | return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.DATA]); |
| 1698 | } | 2684 | } |
| 1699 | | 2685 | |
| 1700 | pub fn targetEndian(elf: *const Elf) std.lang.Endian { | 2686 | fn targetEndian(elf: *const Elf) std.lang.Endian { |
| 1701 | return switch (elf.identData()) { | 2687 | return switch (elf.identData()) { |
| 1702 | .NONE, _ => unreachable, | 2688 | .NONE, _ => unreachable, |
| 1703 | .@"2LSB" => .little, | 2689 | .@"2LSB" => .little, |
| ... | @@ -1731,12 +2717,12 @@ fn targetStore(elf: *const Elf, ptr: anytype, val: @typeInfo(@TypeOf(ptr)).point | ... | @@ -1731,12 +2717,12 @@ fn targetStore(elf: *const Elf, ptr: anytype, val: @typeInfo(@TypeOf(ptr)).point |
| 1731 | }; | 2717 | }; |
| 1732 | } | 2718 | } |
| 1733 | | 2719 | |
| 1734 | pub const EhdrPtr = union(std.elf.CLASS) { | 2720 | const EhdrPtr = union(std.elf.CLASS) { |
| 1735 | NONE: noreturn, | 2721 | NONE: noreturn, |
| 1736 | @"32": *std.elf.Elf32.Ehdr, | 2722 | @"32": *std.elf.Elf32.Ehdr, |
| 1737 | @"64": *std.elf.Elf64.Ehdr, | 2723 | @"64": *std.elf.Elf64.Ehdr, |
| 1738 | }; | 2724 | }; |
| 1739 | pub fn ehdrPtr(elf: *Elf) EhdrPtr { | 2725 | fn ehdrPtr(elf: *Elf) EhdrPtr { |
| 1740 | const slice = elf.ni.ehdr.slice(&elf.mf); | 2726 | const slice = elf.ni.ehdr.slice(&elf.mf); |
| 1741 | return switch (elf.identClass()) { | 2727 | return switch (elf.identClass()) { |
| 1742 | .NONE, _ => unreachable, | 2728 | .NONE, _ => unreachable, |
| ... | @@ -1747,7 +2733,7 @@ pub fn ehdrPtr(elf: *Elf) EhdrPtr { | ... | @@ -1747,7 +2733,7 @@ pub fn ehdrPtr(elf: *Elf) EhdrPtr { |
| 1747 | ), | 2733 | ), |
| 1748 | }; | 2734 | }; |
| 1749 | } | 2735 | } |
| 1750 | pub fn ehdrField( | 2736 | fn ehdrField( |
| 1751 | elf: *Elf, | 2737 | elf: *Elf, |
| 1752 | comptime field: std.meta.FieldEnum(std.elf.Elf64.Ehdr), | 2738 | comptime field: std.meta.FieldEnum(std.elf.Elf64.Ehdr), |
| 1753 | ) @FieldType(std.elf.Elf64.Ehdr, @tagName(field)) { | 2739 | ) @FieldType(std.elf.Elf64.Ehdr, @tagName(field)) { |
| ... | @@ -1756,12 +2742,12 @@ pub fn ehdrField( | ... | @@ -1756,12 +2742,12 @@ pub fn ehdrField( |
| 1756 | }; | 2742 | }; |
| 1757 | } | 2743 | } |
| 1758 | | 2744 | |
| 1759 | pub const PhdrSlice = union(std.elf.CLASS) { | 2745 | const PhdrSlice = union(std.elf.CLASS) { |
| 1760 | NONE: noreturn, | 2746 | NONE: noreturn, |
| 1761 | @"32": []std.elf.Elf32.Phdr, | 2747 | @"32": []std.elf.Elf32.Phdr, |
| 1762 | @"64": []std.elf.Elf64.Phdr, | 2748 | @"64": []std.elf.Elf64.Phdr, |
| 1763 | }; | 2749 | }; |
| 1764 | pub fn phdrSlice(elf: *Elf) PhdrSlice { | 2750 | fn phdrSlice(elf: *Elf) PhdrSlice { |
| 1765 | assert(elf.ehdrField(.type) != .REL); | 2751 | assert(elf.ehdrField(.type) != .REL); |
| 1766 | const slice = elf.ni.phdr.slice(&elf.mf); | 2752 | const slice = elf.ni.phdr.slice(&elf.mf); |
| 1767 | return switch (elf.identClass()) { | 2753 | return switch (elf.identClass()) { |
| ... | @@ -1774,104 +2760,47 @@ pub fn phdrSlice(elf: *Elf) PhdrSlice { | ... | @@ -1774,104 +2760,47 @@ pub fn phdrSlice(elf: *Elf) PhdrSlice { |
| 1774 | }; | 2760 | }; |
| 1775 | } | 2761 | } |
| 1776 | | 2762 | |
| 1777 | pub const ShdrSlice = union(std.elf.CLASS) { | 2763 | const ShdrPtr = union(std.elf.CLASS) { |
| 1778 | NONE: noreturn, | | |
| 1779 | @"32": []std.elf.Elf32.Shdr, | | |
| 1780 | @"64": []std.elf.Elf64.Shdr, | | |
| 1781 | }; | | |
| 1782 | pub fn shdrSlice(elf: *Elf) ShdrSlice { | | |
| 1783 | const slice = elf.ni.shdr.slice(&elf.mf); | | |
| 1784 | return switch (elf.identClass()) { | | |
| 1785 | .NONE, _ => unreachable, | | |
| 1786 | inline else => |class| @unionInit( | | |
| 1787 | ShdrSlice, | | |
| 1788 | @tagName(class), | | |
| 1789 | @ptrCast(@alignCast(slice)), | | |
| 1790 | ), | | |
| 1791 | }; | | |
| 1792 | } | | |
| 1793 | | | |
| 1794 | pub const ShdrPtr = union(std.elf.CLASS) { | | |
| 1795 | NONE: noreturn, | 2764 | NONE: noreturn, |
| 1796 | @"32": *std.elf.Elf32.Shdr, | 2765 | @"32": *std.elf.Elf32.Shdr, |
| 1797 | @"64": *std.elf.Elf64.Shdr, | 2766 | @"64": *std.elf.Elf64.Shdr, |
| 1798 | }; | 2767 | }; |
| 1799 | pub fn shdrPtr(elf: *Elf, shndx: Symbol.Index.Shndx) ShdrPtr { | 2768 | fn shdrPtr(elf: *Elf, shndx: Section.Index) ShdrPtr { |
| 1800 | return switch (elf.shdrSlice()) { | 2769 | const raw_slice = elf.ni.shdr.slice(&elf.mf); |
| 1801 | inline else => |shdrs, class| @unionInit(ShdrPtr, @tagName(class), &shdrs[@intFromEnum(shndx)]), | 2770 | switch (elf.identClass()) { |
| 1802 | }; | | |
| 1803 | } | | |
| 1804 | | | |
| 1805 | pub const SymtabSlice = union(std.elf.CLASS) { | | |
| 1806 | NONE: noreturn, | | |
| 1807 | @"32": []std.elf.Elf32.Sym, | | |
| 1808 | @"64": []std.elf.Elf64.Sym, | | |
| 1809 | }; | | |
| 1810 | pub fn symtabSlice(elf: *Elf) SymtabSlice { | | |
| 1811 | const slice = elf.si.symtab.node(elf).slice(&elf.mf); | | |
| 1812 | return switch (elf.identClass()) { | | |
| 1813 | .NONE, _ => unreachable, | 2771 | .NONE, _ => unreachable, |
| 1814 | inline else => |class| @unionInit(SymtabSlice, @tagName(class), @ptrCast(@alignCast( | 2772 | inline else => |class| { |
| 1815 | slice[0..std.mem.alignBackwardAnyAlign(usize, slice.len, @sizeOf(class.ElfN().Sym))], | 2773 | const shdr_slice: []class.ElfN().Shdr = @ptrCast(@alignCast(raw_slice)); |
| 1816 | ))), | 2774 | const shdr_ptr = &shdr_slice[@intFromEnum(shndx)]; |
| 1817 | }; | 2775 | return @unionInit(ShdrPtr, @tagName(class), shdr_ptr); |
| | 2776 | }, |
| | 2777 | } |
| 1818 | } | 2778 | } |
| 1819 | | 2779 | |
| 1820 | pub const SymPtr = union(std.elf.CLASS) { | 2780 | const SymPtr = union(std.elf.CLASS) { |
| 1821 | NONE: noreturn, | 2781 | NONE: noreturn, |
| 1822 | @"32": *std.elf.Elf32.Sym, | 2782 | @"32": *std.elf.Elf32.Sym, |
| 1823 | @"64": *std.elf.Elf64.Sym, | 2783 | @"64": *std.elf.Elf64.Sym, |
| 1824 | }; | 2784 | }; |
| 1825 | pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr { | 2785 | fn symPtr(elf: *Elf, index: Symbol.Index) SymPtr { |
| 1826 | return switch (elf.symtabSlice()) { | 2786 | const raw_slice = Section.Index.symtab.get(elf).ni.slice(&elf.mf); |
| 1827 | inline else => |syms, class| @unionInit(SymPtr, @tagName(class), &syms[@intFromEnum(si)]), | 2787 | switch (elf.shdrPtr(.symtab)) { |
| 1828 | }; | 2788 | inline else => |shdr, class| { |
| 1829 | } | 2789 | const size = elf.targetLoad(&shdr.size); |
| 1830 | | 2790 | const slice: []class.ElfN().Sym = @ptrCast(@alignCast(raw_slice[0..@intCast(size)])); |
| 1831 | pub fn dynsymSlice(elf: *Elf) SymtabSlice { | 2791 | return @unionInit(SymPtr, @tagName(class), &slice[@intFromEnum(index)]); |
| 1832 | const slice = elf.si.dynsym.node(elf).slice(&elf.mf); | 2792 | }, |
| 1833 | return switch (elf.identClass()) { | 2793 | } |
| 1834 | .NONE, _ => unreachable, | 2794 | } |
| 1835 | inline else => |class| @unionInit(SymtabSlice, @tagName(class), @ptrCast(@alignCast( | 2795 | fn dynsymPtr(elf: *Elf, index: u32) SymPtr { |
| 1836 | slice[0..std.mem.alignBackwardAnyAlign(usize, slice.len, @sizeOf(class.ElfN().Sym))], | 2796 | const raw_slice = elf.shndx.dynsym.get(elf).ni.slice(&elf.mf); |
| 1837 | ))), | 2797 | switch (elf.shdrPtr(elf.shndx.dynsym)) { |
| 1838 | }; | 2798 | inline else => |shdr, class| { |
| 1839 | } | 2799 | const size = elf.targetLoad(&shdr.size); |
| 1840 | | 2800 | const slice: []class.ElfN().Sym = @ptrCast(@alignCast(raw_slice[0..@intCast(size)])); |
| 1841 | fn addSymbolAssumeCapacity(elf: *Elf) Symbol.Index { | 2801 | return @unionInit(SymPtr, @tagName(class), &slice[index]); |
| 1842 | defer elf.symtab.addOneAssumeCapacity().* = .{ | 2802 | }, |
| 1843 | .ni = .none, | 2803 | } |
| 1844 | .loc_relocs = .none, | | |
| 1845 | .target_relocs = .none, | | |
| 1846 | .unused = 0, | | |
| 1847 | }; | | |
| 1848 | return @enumFromInt(elf.symtab.items.len); | | |
| 1849 | } | | |
| 1850 | | | |
| 1851 | fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.Index { | | |
| 1852 | const si = elf.addSymbolAssumeCapacity(); | | |
| 1853 | try si.init(elf, opts); | | |
| 1854 | return si; | | |
| 1855 | } | | |
| 1856 | | | |
| 1857 | pub fn globalSymbol(elf: *Elf, opts: struct { | | |
| 1858 | name: []const u8, | | |
| 1859 | lib_name: ?[]const u8 = null, | | |
| 1860 | type: std.elf.STT, | | |
| 1861 | bind: std.elf.STB = .GLOBAL, | | |
| 1862 | visibility: std.elf.STV = .DEFAULT, | | |
| 1863 | }) !Symbol.Index { | | |
| 1864 | const gpa = elf.base.comp.gpa; | | |
| 1865 | try elf.symtab.ensureUnusedCapacity(gpa, 1); | | |
| 1866 | const global_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name)); | | |
| 1867 | if (!global_gop.found_existing) global_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ | | |
| 1868 | .name = opts.name, | | |
| 1869 | .lib_name = opts.lib_name, | | |
| 1870 | .type = opts.type, | | |
| 1871 | .bind = opts.bind, | | |
| 1872 | .visibility = opts.visibility, | | |
| 1873 | }); | | |
| 1874 | return global_gop.value_ptr.*; | | |
| 1875 | } | 2804 | } |
| 1876 | | 2805 | |
| 1877 | fn navType( | 2806 | fn navType( |
| ... | @@ -1886,97 +2815,135 @@ fn navType( | ... | @@ -1886,97 +2815,135 @@ fn navType( |
| 1886 | else | 2815 | else |
| 1887 | .OBJECT; | 2816 | .OBJECT; |
| 1888 | } | 2817 | } |
| 1889 | fn namedSection(elf: *const Elf, name: []const u8) ?Symbol.Index { | 2818 | fn namedSection(elf: *const Elf, name: []const u8) ?Section.Index { |
| 1890 | if (std.mem.eql(u8, name, ".rodata") or | 2819 | if (std.mem.eql(u8, name, ".rodata") or |
| 1891 | std.mem.startsWith(u8, name, ".rodata.")) return elf.si.rodata; | 2820 | std.mem.startsWith(u8, name, ".rodata.")) return .rodata; |
| 1892 | if (std.mem.eql(u8, name, ".text") or | 2821 | if (std.mem.eql(u8, name, ".text") or |
| 1893 | std.mem.startsWith(u8, name, ".text.")) return elf.si.text; | 2822 | std.mem.startsWith(u8, name, ".text.")) return .text; |
| 1894 | if (std.mem.eql(u8, name, ".data") or | 2823 | if (std.mem.eql(u8, name, ".data") or |
| 1895 | std.mem.startsWith(u8, name, ".data.")) return elf.si.data; | 2824 | std.mem.startsWith(u8, name, ".data.")) return .data; |
| 1896 | if (std.mem.eql(u8, name, ".tdata") or | 2825 | if (std.mem.eql(u8, name, ".tdata") or |
| 1897 | std.mem.startsWith(u8, name, ".tdata.")) return elf.si.tdata; | 2826 | std.mem.startsWith(u8, name, ".tdata.")) return elf.shndx.tdata; |
| 1898 | return null; | 2827 | return null; |
| 1899 | } | 2828 | } |
| 1900 | fn navSection( | | |
| 1901 | elf: *Elf, | | |
| 1902 | ip: *const InternPool, | | |
| 1903 | nav_resolved: @typeInfo(@FieldType(InternPool.Nav, "resolved")).optional.child, | | |
| 1904 | ) Symbol.Index { | | |
| 1905 | if (nav_resolved.@"linksection".toSlice(ip)) |@"linksection"| | | |
| 1906 | if (elf.namedSection(@"linksection")) |si| return si; | | |
| 1907 | return switch (navType( | | |
| 1908 | ip, | | |
| 1909 | nav_resolved, | | |
| 1910 | elf.base.comp.config.any_non_single_threaded, | | |
| 1911 | )) { | | |
| 1912 | else => unreachable, | | |
| 1913 | .FUNC => elf.si.text, | | |
| 1914 | .OBJECT => elf.si.data, | | |
| 1915 | .TLS => elf.si.tdata, | | |
| 1916 | }; | | |
| 1917 | } | | |
| 1918 | fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex { | 2829 | fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex { |
| 1919 | const gpa = zcu.gpa; | 2830 | const gpa = zcu.gpa; |
| 1920 | const ip = &zcu.intern_pool; | 2831 | const ip = &zcu.intern_pool; |
| 1921 | const nav = ip.getNav(nav_index); | 2832 | const nav = ip.getNav(nav_index); |
| 1922 | try elf.symtab.ensureUnusedCapacity(gpa, 1); | | |
| 1923 | const nav_gop = try elf.navs.getOrPut(gpa, nav_index); | | |
| 1924 | if (!nav_gop.found_existing) nav_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ | | |
| 1925 | .name = nav.fqn.toSlice(ip), | | |
| 1926 | .type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded), | | |
| 1927 | }); | | |
| 1928 | return @enumFromInt(nav_gop.index); | | |
| 1929 | } | | |
| 1930 | pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index { | | |
| 1931 | const ip = &zcu.intern_pool; | | |
| 1932 | const nav = ip.getNav(nav_index); | | |
| 1933 | if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{ | | |
| 1934 | .name = @"extern".name.toSlice(ip), | | |
| 1935 | .lib_name = @"extern".lib_name.toSlice(ip), | | |
| 1936 | .type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded), | | |
| 1937 | .bind = switch (@"extern".linkage) { | | |
| 1938 | .internal => .LOCAL, | | |
| 1939 | .strong => .GLOBAL, | | |
| 1940 | .weak => .WEAK, | | |
| 1941 | .link_once => return error.LinkOnceUnsupported, | | |
| 1942 | }, | | |
| 1943 | .visibility = switch (@"extern".visibility) { | | |
| 1944 | .default => .DEFAULT, | | |
| 1945 | .hidden => .HIDDEN, | | |
| 1946 | .protected => .PROTECTED, | | |
| 1947 | }, | | |
| 1948 | }); | | |
| 1949 | const nmi = try elf.navMapIndex(zcu, nav_index); | | |
| 1950 | return nmi.symbol(elf); | | |
| 1951 | } | | |
| 1952 | | 2833 | |
| 1953 | fn uavMapIndex(elf: *Elf, uav_val: InternPool.Index) !Node.UavMapIndex { | 2834 | try elf.ensureUnusedSymbolCapacity(1, .all_local); |
| 1954 | const gpa = elf.base.comp.gpa; | 2835 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 1955 | try elf.symtab.ensureUnusedCapacity(gpa, 1); | 2836 | try elf.navs.ensureUnusedCapacity(gpa, 1); |
| 1956 | const uav_gop = try elf.uavs.getOrPut(gpa, uav_val); | 2837 | |
| 1957 | if (!uav_gop.found_existing) | 2838 | const nav_gop = elf.navs.getOrPutAssumeCapacity(nav_index); |
| 1958 | uav_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ .type = .OBJECT }); | 2839 | const nmi: Node.NavMapIndex = @enumFromInt(nav_gop.index); |
| 1959 | return @enumFromInt(uav_gop.index); | 2840 | if (!nav_gop.found_existing) { |
| 1960 | } | 2841 | const sym_type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded); |
| 1961 | pub fn uavSymbol(elf: *Elf, uav_val: InternPool.Index) !Symbol.Index { | 2842 | const shndx: Section.Index = section: { |
| 1962 | const umi = try elf.uavMapIndex(uav_val); | 2843 | if (nav.resolved.?.@"linksection".toSlice(ip)) |@"linksection"| { |
| 1963 | return umi.symbol(elf); | 2844 | if (elf.namedSection(@"linksection")) |shndx| break :section shndx; |
| | 2845 | } |
| | 2846 | break :section switch (sym_type) { |
| | 2847 | else => unreachable, |
| | 2848 | .FUNC => .text, |
| | 2849 | .OBJECT => .data, |
| | 2850 | .TLS => elf.shndx.tdata, |
| | 2851 | }; |
| | 2852 | }; |
| | 2853 | const alignment: InternPool.Alignment = switch (Type.fromInterned(nav.resolved.?.type).zigTypeTag(zcu)) { |
| | 2854 | .@"fn" => a: { |
| | 2855 | const mod = zcu.navFileScope(nav_index).mod.?; |
| | 2856 | const target = &mod.resolved_target.result; |
| | 2857 | const min = target_util.minFunctionAlignment(target); |
| | 2858 | break :a switch (nav.resolved.?.@"align") { |
| | 2859 | else => |a| a.maxStrict(min), |
| | 2860 | .none => switch (mod.optimize_mode) { |
| | 2861 | .Debug, |
| | 2862 | .ReleaseSafe, |
| | 2863 | .ReleaseFast, |
| | 2864 | => target_util.defaultFunctionAlignment(target), |
| | 2865 | .ReleaseSmall => min, |
| | 2866 | }, |
| | 2867 | }; |
| | 2868 | }, |
| | 2869 | else => switch (nav.resolved.?.@"align") { |
| | 2870 | .none => Type.fromInterned(nav.resolved.?.type).abiAlignment(zcu), |
| | 2871 | else => |a| a, |
| | 2872 | }, |
| | 2873 | }; |
| | 2874 | const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{ |
| | 2875 | .alignment = alignment.toStdMem(), |
| | 2876 | }); |
| | 2877 | nav_gop.value_ptr.* = .{ |
| | 2878 | .lsi = elf.addLocalSymbolAssumeCapacity(.{ |
| | 2879 | .node = node, |
| | 2880 | .name = try elf.string(.strtab, nav.fqn.toSlice(ip)), |
| | 2881 | .value = 0, |
| | 2882 | .size = 0, |
| | 2883 | .type = sym_type, |
| | 2884 | .shndx = shndx, |
| | 2885 | }), |
| | 2886 | .first_reloc = .none, |
| | 2887 | }; |
| | 2888 | elf.nodes.appendAssumeCapacity(.{ .nav = nmi }); |
| | 2889 | } |
| | 2890 | return nmi; |
| 1964 | } | 2891 | } |
| 1965 | | 2892 | |
| 1966 | pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index { | 2893 | fn uavMapIndex( |
| | 2894 | elf: *Elf, |
| | 2895 | uav_val: InternPool.Index, |
| | 2896 | uav_align: InternPool.Alignment, |
| | 2897 | ) !Node.UavMapIndex { |
| 1967 | const gpa = elf.base.comp.gpa; | 2898 | const gpa = elf.base.comp.gpa; |
| 1968 | try elf.symtab.ensureUnusedCapacity(gpa, 1); | 2899 | const zcu = elf.base.comp.zcu.?; |
| 1969 | const lazy_gop = try elf.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty); | 2900 | |
| 1970 | if (!lazy_gop.found_existing) { | 2901 | try elf.ensureUnusedSymbolCapacity(1, .all_local); |
| 1971 | lazy_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ | 2902 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 1972 | .type = switch (lazy.kind) { | 2903 | try elf.uavs.ensureUnusedCapacity(gpa, 1); |
| 1973 | .code => .FUNC, | 2904 | try elf.pending_uavs.ensureUnusedCapacity(gpa, 1); |
| 1974 | .const_data => .OBJECT, | 2905 | |
| 1975 | }, | 2906 | const abi_align = Value.fromInterned(uav_val).typeOf(zcu).abiAlignment(zcu); |
| | 2907 | const resolved_align: InternPool.Alignment = switch (uav_align) { |
| | 2908 | .none => abi_align, |
| | 2909 | else => |a| a.minStrict(abi_align), |
| | 2910 | }; |
| | 2911 | |
| | 2912 | const uav_gop = elf.uavs.getOrPutAssumeCapacity(uav_val); |
| | 2913 | const umi: Node.UavMapIndex = @enumFromInt(uav_gop.index); |
| | 2914 | if (!uav_gop.found_existing) { |
| | 2915 | const shndx: Section.Index = .data; |
| | 2916 | const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{ |
| | 2917 | .moved = true, // see assert at end of `flushUav` |
| | 2918 | .alignment = resolved_align.toStdMem(), |
| 1976 | }); | 2919 | }); |
| 1977 | elf.synth_prog_node.increaseEstimatedTotalItems(1); | 2920 | var name_buf: [32]u8 = undefined; |
| | 2921 | const name = std.fmt.bufPrint( |
| | 2922 | &name_buf, |
| | 2923 | "__anon_{d}", |
| | 2924 | .{@intFromEnum(uav_val)}, |
| | 2925 | ) catch unreachable; |
| | 2926 | uav_gop.value_ptr.* = .{ |
| | 2927 | .lsi = elf.addLocalSymbolAssumeCapacity(.{ |
| | 2928 | .node = node, |
| | 2929 | .name = try elf.string(.strtab, name), |
| | 2930 | .value = 0, |
| | 2931 | .size = 0, |
| | 2932 | .type = .OBJECT, |
| | 2933 | .shndx = shndx, |
| | 2934 | }), |
| | 2935 | .first_reloc = .none, |
| | 2936 | }; |
| | 2937 | elf.nodes.appendAssumeCapacity(.{ .uav = umi }); |
| | 2938 | elf.const_prog_node.increaseEstimatedTotalItems(1); |
| | 2939 | elf.pending_uavs.appendAssumeCapacity(umi); |
| | 2940 | } else { |
| | 2941 | const node = uav_gop.value_ptr.lsi.index().ptr(elf).node; |
| | 2942 | if (resolved_align.toStdMem().order(node.alignment(&elf.mf)).compare(.gt)) { |
| | 2943 | node.realign(&elf.mf, resolved_align.toStdMem()); |
| | 2944 | } |
| 1978 | } | 2945 | } |
| 1979 | return lazy_gop.value_ptr.*; | 2946 | return umi; |
| 1980 | } | 2947 | } |
| 1981 | | 2948 | |
| 1982 | pub fn loadInput(elf: *Elf, input: link.Input) (Io.File.Reader.SizeError || | 2949 | pub fn loadInput(elf: *Elf, input: link.Input) (Io.File.Reader.SizeError || |
| ... | @@ -2081,22 +3048,23 @@ fn loadObject( | ... | @@ -2081,22 +3048,23 @@ fn loadObject( |
| 2081 | const diags = &comp.link_diags; | 3048 | const diags = &comp.link_diags; |
| 2082 | const r = &fr.interface; | 3049 | const r = &fr.interface; |
| 2083 | | 3050 | |
| 2084 | const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len); | 3051 | const input_index: Node.InputIndex = @enumFromInt(elf.inputs.items.len); |
| 2085 | log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) }); | 3052 | log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) }); |
| 2086 | const ident = try r.peek(std.elf.EI.OSABI); | 3053 | try elf.checkInputIdent(path, r); |
| 2087 | if (!std.mem.eql(u8, ident[0..std.elf.MAGIC.len], std.elf.MAGIC)) return error.BadMagic; | 3054 | try elf.ensureUnusedSymbolCapacity(1, .all_local); |
| 2088 | if (!std.mem.eql(u8, ident[std.elf.MAGIC.len..], elf.mf.memory_map.memory[std.elf.MAGIC.len..ident.len])) | | |
| 2089 | return diags.failParse(path, "bad ident", .{}); | | |
| 2090 | try elf.symtab.ensureUnusedCapacity(gpa, 1); | | |
| 2091 | try elf.inputs.ensureUnusedCapacity(gpa, 1); | 3055 | try elf.inputs.ensureUnusedCapacity(gpa, 1); |
| | 3056 | const file_symbol = elf.addLocalSymbolAssumeCapacity(.{ |
| | 3057 | .node = .none, |
| | 3058 | .name = try elf.string(.strtab, std.fs.path.stem(member orelse path.sub_path)), |
| | 3059 | .value = 0, |
| | 3060 | .size = 0, |
| | 3061 | .type = .FILE, |
| | 3062 | .shndx = .ABS, |
| | 3063 | }); |
| 2092 | elf.inputs.addOneAssumeCapacity().* = .{ | 3064 | elf.inputs.addOneAssumeCapacity().* = .{ |
| 2093 | .path = path, | 3065 | .path = path, |
| 2094 | .member = if (member) |m| try gpa.dupe(u8, m) else null, | 3066 | .member = if (member) |m| try gpa.dupe(u8, m) else null, |
| 2095 | .si = try elf.initSymbolAssumeCapacity(.{ | 3067 | .file_symbol = file_symbol, |
| 2096 | .name = std.fs.path.stem(member orelse path.sub_path), | | |
| 2097 | .type = .FILE, | | |
| 2098 | .shndx = .ABS, | | |
| 2099 | }), | | |
| 2100 | }; | 3068 | }; |
| 2101 | const target_endian = elf.targetEndian(); | 3069 | const target_endian = elf.targetEndian(); |
| 2102 | switch (elf.identClass()) { | 3070 | switch (elf.identClass()) { |
| ... | @@ -2108,17 +3076,17 @@ fn loadObject( | ... | @@ -2108,17 +3076,17 @@ fn loadObject( |
| 2108 | if (ehdr.machine != elf.ehdrField(.machine)) | 3076 | if (ehdr.machine != elf.ehdrField(.machine)) |
| 2109 | return diags.failParse(path, "bad machine", .{}); | 3077 | return diags.failParse(path, "bad machine", .{}); |
| 2110 | if (ehdr.shoff == 0 or ehdr.shnum <= 1) return; | 3078 | if (ehdr.shoff == 0 or ehdr.shnum <= 1) return; |
| 2111 | if (ehdr.shoff + ehdr.shentsize * ehdr.shnum > fl.size) | 3079 | if (ehdr.shoff + @as(u64, ehdr.shentsize) * @as(u64, ehdr.shnum) > fl.size) |
| 2112 | return diags.failParse(path, "bad section header location", .{}); | 3080 | return diags.failParse(path, "bad section header location", .{}); |
| 2113 | if (ehdr.shentsize < @sizeOf(ElfN.Shdr)) | 3081 | if (ehdr.shentsize < @sizeOf(ElfN.Shdr)) |
| 2114 | return diags.failParse(path, "unsupported shentsize", .{}); | 3082 | return diags.failParse(path, "unsupported shentsize", .{}); |
| 2115 | const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, si: Symbol.Index }, ehdr.shnum); | 3083 | const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, isi: ?InputSection.Index }, ehdr.shnum); |
| 2116 | defer gpa.free(sections); | 3084 | defer gpa.free(sections); |
| 2117 | try fr.seekTo(fl.offset + ehdr.shoff); | 3085 | try fr.seekTo(fl.offset + ehdr.shoff); |
| 2118 | for (sections) |*section| { | 3086 | for (sections) |*section| { |
| 2119 | section.* = .{ | 3087 | section.* = .{ |
| 2120 | .shdr = try r.peekStruct(ElfN.Shdr, target_endian), | 3088 | .shdr = try r.peekStruct(ElfN.Shdr, target_endian), |
| 2121 | .si = .null, | 3089 | .isi = null, |
| 2122 | }; | 3090 | }; |
| 2123 | try r.discardAll(ehdr.shentsize); | 3091 | try r.discardAll(ehdr.shentsize); |
| 2124 | switch (section.shdr.type) { | 3092 | switch (section.shdr.type) { |
| ... | @@ -2140,42 +3108,49 @@ fn loadObject( | ... | @@ -2140,42 +3108,49 @@ fn loadObject( |
| 2140 | }; | 3108 | }; |
| 2141 | defer gpa.free(shstrtab); | 3109 | defer gpa.free(shstrtab); |
| 2142 | try elf.nodes.ensureUnusedCapacity(gpa, ehdr.shnum - 1); | 3110 | try elf.nodes.ensureUnusedCapacity(gpa, ehdr.shnum - 1); |
| 2143 | try elf.symtab.ensureUnusedCapacity(gpa, ehdr.shnum - 1); | | |
| 2144 | try elf.input_sections.ensureUnusedCapacity(gpa, ehdr.shnum - 1); | 3111 | try elf.input_sections.ensureUnusedCapacity(gpa, ehdr.shnum - 1); |
| 2145 | for (sections[1..]) |*section| switch (section.shdr.type) { | 3112 | for (sections[1..]) |*section| switch (section.shdr.type) { |
| 2146 | else => {}, | 3113 | else => {}, |
| 2147 | .PROGBITS, .NOBITS => { | 3114 | .PROGBITS, .NOBITS => { |
| 2148 | if (section.shdr.name >= shstrtab.len) continue; | 3115 | if (section.shdr.name >= shstrtab.len) continue; |
| 2149 | const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0); | 3116 | const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0); |
| 2150 | const parent_si = elf.namedSection(name) orelse continue; | 3117 | const shndx: Section.Index = elf.namedSection(name) orelse shndx: { |
| 2151 | const ni = try elf.mf.addLastChildNode(gpa, parent_si.node(elf), .{ | 3118 | // TODO: actually generate a .bss section. For now, just throw it into `.data`. |
| | 3119 | if (std.mem.eql(u8, name, ".bss") or |
| | 3120 | std.mem.startsWith(u8, name, ".bss.")) break :shndx .data; |
| | 3121 | if (std.mem.eql(u8, name, ".tbss") or |
| | 3122 | std.mem.startsWith(u8, name, ".tbss.")) break :shndx elf.shndx.tdata; |
| | 3123 | break :shndx .UNDEF; |
| | 3124 | }; |
| | 3125 | if (shndx == .UNDEF) continue; |
| | 3126 | const ni = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{ |
| 2152 | .size = section.shdr.size, | 3127 | .size = section.shdr.size, |
| 2153 | .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert( | 3128 | .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert( |
| 2154 | usize, | 3129 | usize, |
| 2155 | @intCast(@max(section.shdr.addralign, 1)), | 3130 | @intCast(@max(section.shdr.addralign, 1)), |
| 2156 | )), | 3131 | )), |
| 2157 | .moved = true, | 3132 | .moved = true, // see assert at end of `flushInputSection` |
| 2158 | }); | 3133 | }); |
| 2159 | elf.nodes.appendAssumeCapacity(.{ | 3134 | elf.nodes.appendAssumeCapacity(.{ |
| 2160 | .input_section = @enumFromInt(elf.input_sections.items.len), | 3135 | .input_section = @enumFromInt(elf.input_sections.items.len), |
| 2161 | }); | 3136 | }); |
| 2162 | section.si = try elf.initSymbolAssumeCapacity(.{ | 3137 | section.isi = @enumFromInt(elf.input_sections.items.len); |
| 2163 | .type = .SECTION, | | |
| 2164 | .shndx = parent_si.shndx(elf), | | |
| 2165 | }); | | |
| 2166 | section.si.get(elf).ni = ni; | | |
| 2167 | elf.input_sections.addOneAssumeCapacity().* = .{ | 3138 | elf.input_sections.addOneAssumeCapacity().* = .{ |
| 2168 | .ii = ii, | 3139 | .input = input_index, |
| 2169 | .si = section.si, | | |
| 2170 | .file_location = .{ | 3140 | .file_location = .{ |
| 2171 | .offset = fl.offset + section.shdr.offset, | 3141 | .offset = fl.offset + section.shdr.offset, |
| 2172 | .size = section.shdr.size, | 3142 | .size = if (section.shdr.type == .NOBITS) 0 else section.shdr.size, |
| 2173 | }, | 3143 | }, |
| | 3144 | // The section vaddr is initially 0, because the symbol addresses are |
| | 3145 | // zero-based. This will eventually be updated by `flushMoved`. |
| | 3146 | .vaddr = 0, |
| | 3147 | .node = ni, |
| | 3148 | .first_reloc = .none, |
| 2174 | }; | 3149 | }; |
| 2175 | elf.synth_prog_node.increaseEstimatedTotalItems(1); | 3150 | elf.synth_prog_node.increaseEstimatedTotalItems(1); |
| 2176 | }, | 3151 | }, |
| 2177 | }; | 3152 | }; |
| 2178 | var symmap: std.ArrayList(Symbol.Index) = .empty; | 3153 | var symmap: std.ArrayList(Symbol.Id) = .empty; |
| 2179 | defer symmap.deinit(gpa); | 3154 | defer symmap.deinit(gpa); |
| 2180 | for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) { | 3155 | for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) { |
| 2181 | else => {}, | 3156 | else => {}, |
| ... | @@ -2206,105 +3181,132 @@ fn loadObject( | ... | @@ -2206,105 +3181,132 @@ fn loadObject( |
| 2206 | ), 1) catch continue; | 3181 | ), 1) catch continue; |
| 2207 | symmap.clearRetainingCapacity(); | 3182 | symmap.clearRetainingCapacity(); |
| 2208 | try symmap.resize(gpa, symnum); | 3183 | try symmap.resize(gpa, symnum); |
| 2209 | try elf.symtab.ensureUnusedCapacity(gpa, symnum); | 3184 | try elf.ensureUnusedSymbolCapacity(symnum, .maybe_global); |
| 2210 | try elf.globals.ensureUnusedCapacity(gpa, symnum); | | |
| 2211 | try fr.seekTo(fl.offset + symtab.shdr.offset + symtab.shdr.entsize); | 3185 | try fr.seekTo(fl.offset + symtab.shdr.offset + symtab.shdr.entsize); |
| 2212 | for (symmap.items) |*si| { | 3186 | for (symmap.items) |*si| { |
| 2213 | si.* = .null; | 3187 | si.* = .null; |
| 2214 | const input_sym = try r.peekStruct(ElfN.Sym, target_endian); | 3188 | const input_sym = try r.peekStruct(ElfN.Sym, target_endian); |
| 2215 | try r.discardAll64(symtab.shdr.entsize); | 3189 | try r.discardAll64(symtab.shdr.entsize); |
| 2216 | if (input_sym.name >= strtab.len or input_sym.shndx == std.elf.SHN_UNDEF or | 3190 | if (input_sym.name >= strtab.len or input_sym.shndx >= ehdr.shnum) continue; |
| 2217 | input_sym.shndx >= ehdr.shnum) continue; | 3191 | |
| 2218 | switch (input_sym.info.type) { | 3192 | const name = std.mem.sliceTo(strtab[input_sym.name..], 0); |
| 2219 | .NOTYPE, .OBJECT, .FUNC => {}, | 3193 | |
| 2220 | .SECTION => { | 3194 | const sym_type: std.elf.STT = switch (input_sym.info.type) { |
| 2221 | const section = &sections[input_sym.shndx]; | 3195 | .NOTYPE, .OBJECT, .FUNC, .TLS => |t| t, |
| 2222 | if (input_sym.value == section.shdr.addr) si.* = section.si; | 3196 | .SECTION => .NOTYPE, |
| | 3197 | .FILE, .COMMON, _ => continue, |
| | 3198 | }; |
| | 3199 | |
| | 3200 | if (input_sym.shndx == std.elf.SHN_UNDEF) switch (input_sym.info.bind) { |
| | 3201 | _ => |bind| return diags.failParse( |
| | 3202 | path, |
| | 3203 | "symbol '{s}' has unsupported binding (0x{x})", |
| | 3204 | .{ name, bind }, |
| | 3205 | ), |
| | 3206 | .LOCAL => continue, |
| | 3207 | .GLOBAL, .WEAK => |bind| { |
| | 3208 | si.* = elf.addGlobalSymbolAssumeCapacity(.{ |
| | 3209 | .node = .none, |
| | 3210 | .name = try .string(elf, name), |
| | 3211 | .value = input_sym.value, |
| | 3212 | .size = input_sym.size, |
| | 3213 | .type = sym_type, |
| | 3214 | .bind = if (bind == .WEAK) .weak else .strong, |
| | 3215 | .visibility = input_sym.other.visibility, |
| | 3216 | .shndx = .UNDEF, |
| | 3217 | }) catch |err| switch (err) { |
| | 3218 | error.MultipleDefinitions => unreachable, // shndx is .UNDEF |
| | 3219 | }; |
| 2223 | continue; | 3220 | continue; |
| 2224 | }, | 3221 | }, |
| 2225 | else => continue, | 3222 | }; |
| 2226 | } | 3223 | |
| 2227 | const name = std.mem.sliceTo(strtab[input_sym.name..], 0); | 3224 | const input_section_node = (sections[input_sym.shndx].isi orelse continue).node(elf); |
| 2228 | const parent_si = sections[input_sym.shndx].si; | 3225 | |
| 2229 | si.* = try elf.initSymbolAssumeCapacity(.{ | | |
| 2230 | .name = name, | | |
| 2231 | .value = input_sym.value, | | |
| 2232 | .size = input_sym.size, | | |
| 2233 | .type = input_sym.info.type, | | |
| 2234 | .bind = input_sym.info.bind, | | |
| 2235 | .visibility = input_sym.other.visibility, | | |
| 2236 | .shndx = parent_si.shndx(elf), | | |
| 2237 | }); | | |
| 2238 | si.get(elf).ni = parent_si.get(elf).ni; | | |
| 2239 | switch (input_sym.info.bind) { | 3226 | switch (input_sym.info.bind) { |
| 2240 | else => {}, | 3227 | _ => |bind| return diags.failParse( |
| 2241 | .GLOBAL => { | 3228 | path, |
| 2242 | const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad( | 3229 | "symbol '{s}' has unsupported binding (0x{x})", |
| 2243 | &@field(elf.symPtr(si.*), @tagName(class)).name, | 3230 | .{ name, bind }, |
| 2244 | )); | 3231 | ), |
| 2245 | if (gop.found_existing) switch (elf.targetLoad( | 3232 | .LOCAL => { |
| 2246 | switch (elf.symPtr(gop.value_ptr.*)) { | 3233 | const lsi = elf.addLocalSymbolAssumeCapacity(.{ |
| 2247 | inline else => |sym| &sym.info, | 3234 | .node = input_section_node, |
| 2248 | }, | 3235 | .name = try elf.string(.strtab, name), |
| 2249 | ).bind) { | 3236 | .value = input_sym.value, |
| 2250 | else => unreachable, | 3237 | .size = input_sym.size, |
| 2251 | .GLOBAL => return diags.failParse( | 3238 | .type = sym_type, |
| | 3239 | .shndx = elf.getNodeShndx(input_section_node), |
| | 3240 | }); |
| | 3241 | si.* = .local(lsi); |
| | 3242 | }, |
| | 3243 | .GLOBAL, .WEAK => |bind| { |
| | 3244 | si.* = elf.addGlobalSymbolAssumeCapacity(.{ |
| | 3245 | .node = input_section_node, |
| | 3246 | .name = try .string(elf, name), |
| | 3247 | .value = input_sym.value, |
| | 3248 | .size = input_sym.size, |
| | 3249 | .type = sym_type, |
| | 3250 | .bind = if (bind == .WEAK) .weak else .strong, |
| | 3251 | .visibility = input_sym.other.visibility, |
| | 3252 | .shndx = elf.getNodeShndx(input_section_node), |
| | 3253 | }) catch |err| switch (err) { |
| | 3254 | error.MultipleDefinitions => return diags.failParse( |
| 2252 | path, | 3255 | path, |
| 2253 | "multiple definitions of '{s}'", | 3256 | "multiple definitions of '{s}'", |
| 2254 | .{name}, | 3257 | .{name}, |
| 2255 | ), | 3258 | ), |
| 2256 | .WEAK => {}, | | |
| 2257 | }; | 3259 | }; |
| 2258 | gop.value_ptr.* = si.*; | | |
| 2259 | }, | | |
| 2260 | .WEAK => { | | |
| 2261 | const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad( | | |
| 2262 | &@field(elf.symPtr(si.*), @tagName(class)).name, | | |
| 2263 | )); | | |
| 2264 | if (!gop.found_existing) gop.value_ptr.* = si.*; | | |
| 2265 | }, | 3260 | }, |
| 2266 | } | 3261 | } |
| 2267 | } | 3262 | } |
| 2268 | for (sections[1..]) |*rels| switch (rels.shdr.type) { | 3263 | for (sections[1..]) |*rel_sec| switch (rel_sec.shdr.type) { |
| 2269 | else => {}, | 3264 | else => {}, |
| 2270 | inline .REL, .RELA => |sht| { | 3265 | inline .REL, .RELA => |sht| { |
| 2271 | if (rels.shdr.link != symtab_shndx or rels.shdr.info == std.elf.SHN_UNDEF or | 3266 | if (rel_sec.shdr.link != symtab_shndx or rel_sec.shdr.info == std.elf.SHN_UNDEF or |
| 2272 | rels.shdr.info >= ehdr.shnum) continue; | 3267 | rel_sec.shdr.info >= ehdr.shnum) continue; |
| 2273 | const Rel = switch (sht) { | 3268 | const Rel = switch (sht) { |
| 2274 | else => comptime unreachable, | 3269 | else => comptime unreachable, |
| 2275 | .REL => ElfN.Rel, | 3270 | .REL => ElfN.Rel, |
| 2276 | .RELA => ElfN.Rela, | 3271 | .RELA => ElfN.Rela, |
| 2277 | }; | 3272 | }; |
| 2278 | if (rels.shdr.entsize < @sizeOf(Rel)) | 3273 | if (rel_sec.shdr.entsize < @sizeOf(Rel)) |
| 2279 | return diags.failParse(path, "unsupported rel entsize", .{}); | 3274 | return diags.failParse(path, "unsupported rel entsize", .{}); |
| 2280 | | 3275 | |
| 2281 | const loc_sec = &sections[rels.shdr.info]; | 3276 | const loc_sec = &sections[rel_sec.shdr.info]; |
| 2282 | if (loc_sec.si == .null) continue; | 3277 | const loc_node = (loc_sec.isi orelse continue).node(elf); |
| 2283 | const loc_sym = loc_sec.si.get(elf); | 3278 | elf.resetNodeRelocs(loc_node); |
| 2284 | assert(loc_sym.loc_relocs == .none); | | |
| 2285 | loc_sym.loc_relocs = @enumFromInt(elf.relocs.items.len); | | |
| 2286 | | 3279 | |
| 2287 | const relnum = std.math.divExact( | 3280 | const relnum = std.math.divExact( |
| 2288 | u32, | 3281 | u32, |
| 2289 | @intCast(rels.shdr.size), | 3282 | @intCast(rel_sec.shdr.size), |
| 2290 | @intCast(rels.shdr.entsize), | 3283 | @intCast(rel_sec.shdr.entsize), |
| 2291 | ) catch return diags.failParse( | 3284 | ) catch return diags.failParse( |
| 2292 | path, | 3285 | path, |
| 2293 | "relocation section size (0x{x}) is not a multiple of entsize (0x{x})", | 3286 | "relocation section size (0x{x}) is not a multiple of entsize (0x{x})", |
| 2294 | .{ rels.shdr.size, rels.shdr.entsize }, | 3287 | .{ rel_sec.shdr.size, rel_sec.shdr.entsize }, |
| 2295 | ); | 3288 | ); |
| 2296 | try elf.ensureUnusedRelocCapacity(loc_sec.si, relnum); | 3289 | try elf.ensureUnusedRelocCapacity(loc_node, relnum); |
| 2297 | try fr.seekTo(fl.offset + rels.shdr.offset); | 3290 | try fr.seekTo(fl.offset + rel_sec.shdr.offset); |
| 2298 | for (0..relnum) |_| { | 3291 | for (0..relnum) |_| { |
| 2299 | const rel = try r.peekStruct(Rel, target_endian); | 3292 | const rel = try r.peekStruct(Rel, target_endian); |
| 2300 | try r.discardAll64(rels.shdr.entsize); | 3293 | try r.discardAll64(rel_sec.shdr.entsize); |
| 2301 | if (rel.info.sym == 0 or rel.info.sym > symnum) continue; | 3294 | if (rel.info.sym == 0) continue; |
| 2302 | const target_si = symmap.items[rel.info.sym - 1]; | 3295 | if (rel.info.sym > symnum) return diags.failParse( |
| 2303 | if (target_si == .null) continue; | 3296 | path, |
| | 3297 | "relocation target symbol index {d} exceeds symtab size", |
| | 3298 | .{rel.info.sym}, |
| | 3299 | ); |
| | 3300 | const target = symmap.items[rel.info.sym - 1]; |
| | 3301 | if (target == Symbol.Id.null) return diags.failParse( |
| | 3302 | path, |
| | 3303 | "unsupported symbol at index {d} required for relocation", |
| | 3304 | .{rel.info.sym}, |
| | 3305 | ); |
| 2304 | elf.addRelocAssumeCapacity( | 3306 | elf.addRelocAssumeCapacity( |
| 2305 | loc_sec.si, | 3307 | loc_node, |
| 2306 | rel.offset - loc_sec.shdr.addr, | 3308 | rel.offset - loc_sec.shdr.addr, |
| 2307 | target_si, | 3309 | target, |
| 2308 | rel.addend, | 3310 | rel.addend, |
| 2309 | .wrap(rel.info.type, elf), | 3311 | .wrap(rel.info.type, elf), |
| 2310 | ); | 3312 | ); |
| ... | @@ -2322,10 +3324,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { | ... | @@ -2322,10 +3324,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { |
| 2322 | const r = &fr.interface; | 3324 | const r = &fr.interface; |
| 2323 | | 3325 | |
| 2324 | log.debug("loadDso({f})", .{path.fmtEscapeString()}); | 3326 | log.debug("loadDso({f})", .{path.fmtEscapeString()}); |
| 2325 | const ident = try r.peek(std.elf.EI.NIDENT); | 3327 | try elf.checkInputIdent(path, r); |
| 2326 | 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])) | | |
| 2328 | return diags.failParse(path, "bad ident", .{}); | | |
| 2329 | const target_endian = elf.targetEndian(); | 3328 | const target_endian = elf.targetEndian(); |
| 2330 | switch (elf.identClass()) { | 3329 | switch (elf.identClass()) { |
| 2331 | .NONE, _ => unreachable, | 3330 | .NONE, _ => unreachable, |
| ... | @@ -2393,7 +3392,62 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { | ... | @@ -2393,7 +3392,62 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { |
| 2393 | } | 3392 | } |
| 2394 | fn loadDsoExact(elf: *Elf, name: []const u8) !void { | 3393 | fn loadDsoExact(elf: *Elf, name: []const u8) !void { |
| 2395 | log.debug("loadDsoExact({f})", .{std.zig.fmtString(name)}); | 3394 | log.debug("loadDsoExact({f})", .{std.zig.fmtString(name)}); |
| 2396 | try elf.needed.put(elf.base.comp.gpa, try elf.string(.dynstr, name), {}); | 3395 | if (elf.shndx.dynamic != .UNDEF) { |
| | 3396 | try elf.needed.put(elf.base.comp.gpa, try elf.string(.dynstr, name), {}); |
| | 3397 | } |
| | 3398 | } |
| | 3399 | |
| | 3400 | /// Validates that the `std.elf.Ident` present at the start of `r` is a compatible link input. |
| | 3401 | /// |
| | 3402 | /// Returns an error if it is incompatible, or if the ident is broken or missing. |
| | 3403 | /// |
| | 3404 | /// Does not advance the position of `r`. Requires `r` to have a 16-byte buffer. |
| | 3405 | fn checkInputIdent( |
| | 3406 | elf: *const Elf, |
| | 3407 | path: std.Build.Cache.Path, |
| | 3408 | r: *Io.Reader, |
| | 3409 | ) !void { |
| | 3410 | const diags = &elf.base.comp.link_diags; |
| | 3411 | |
| | 3412 | const ident = try r.peekStructPointer(std.elf.Ident); |
| | 3413 | const target: *const std.elf.Ident = @ptrCast(elf.mf.memory_map.memory[0..@sizeOf(std.elf.Ident)]); |
| | 3414 | |
| | 3415 | if (!std.mem.eql(u8, &ident.magic, std.elf.MAGIC)) { |
| | 3416 | return error.BadMagic; |
| | 3417 | } |
| | 3418 | |
| | 3419 | if (ident.class != target.class) return diags.failParse( |
| | 3420 | path, |
| | 3421 | "bad ELF class ({?s})", |
| | 3422 | .{std.enums.tagName(std.elf.CLASS, ident.class)}, |
| | 3423 | ); |
| | 3424 | if (ident.data != target.data) return diags.failParse( |
| | 3425 | path, |
| | 3426 | "bad ELF data encoding ({?s})", |
| | 3427 | .{std.enums.tagName(std.elf.DATA, ident.data)}, |
| | 3428 | ); |
| | 3429 | if (ident.version != target.version) return diags.failParse( |
| | 3430 | path, |
| | 3431 | "bad ELF version ({d})", |
| | 3432 | .{ident.version}, |
| | 3433 | ); |
| | 3434 | |
| | 3435 | // OSABI is a bit more complex. On Linux, `.NONE` and `.GNU` are both valid and both common. |
| | 3436 | // It sounds reasonable to allow the value we chose *and* allow `.NONE`. |
| | 3437 | const expect_abiversion: u8 = abiver: { |
| | 3438 | if (ident.osabi == .NONE) break :abiver 0; |
| | 3439 | if (ident.osabi == target.osabi) break :abiver target.abiversion; |
| | 3440 | return diags.failParse( |
| | 3441 | path, |
| | 3442 | "bad ELF OS/ABI ({?s})", |
| | 3443 | .{std.enums.tagName(std.elf.OSABI, ident.osabi)}, |
| | 3444 | ); |
| | 3445 | }; |
| | 3446 | if (ident.abiversion != expect_abiversion) return diags.failParse( |
| | 3447 | path, |
| | 3448 | "bad ELF ABI version ({d})", |
| | 3449 | .{ident.abiversion}, |
| | 3450 | ); |
| 2397 | } | 3451 | } |
| 2398 | | 3452 | |
| 2399 | pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void { | 3453 | pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void { |
| ... | @@ -2406,20 +3460,27 @@ pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void { | ... | @@ -2406,20 +3460,27 @@ pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void { |
| 2406 | fn prelinkInner(elf: *Elf) !void { | 3460 | fn prelinkInner(elf: *Elf) !void { |
| 2407 | const comp = elf.base.comp; | 3461 | const comp = elf.base.comp; |
| 2408 | const gpa = comp.gpa; | 3462 | const gpa = comp.gpa; |
| 2409 | try elf.symtab.ensureUnusedCapacity(gpa, 1); | 3463 | try elf.ensureUnusedSymbolCapacity(1, .all_local); |
| 2410 | try elf.inputs.ensureUnusedCapacity(gpa, 1); | 3464 | try elf.inputs.ensureUnusedCapacity(gpa, 1); |
| 2411 | const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{ | 3465 | const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{ |
| 2412 | std.fs.path.stem(elf.base.emit.sub_path), | 3466 | std.fs.path.stem(elf.base.emit.sub_path), |
| 2413 | }); | 3467 | }); |
| 2414 | defer gpa.free(zcu_name); | 3468 | defer gpa.free(zcu_name); |
| 2415 | const si = try elf.initSymbolAssumeCapacity(.{ .name = zcu_name, .type = .FILE, .shndx = .ABS }); | 3469 | const zcu_file_symbol = elf.addLocalSymbolAssumeCapacity(.{ |
| | 3470 | .node = .none, |
| | 3471 | .name = try elf.string(.strtab, zcu_name), |
| | 3472 | .value = 0, |
| | 3473 | .size = 0, |
| | 3474 | .type = .FILE, |
| | 3475 | .shndx = .ABS, |
| | 3476 | }); |
| 2416 | elf.inputs.addOneAssumeCapacity().* = .{ | 3477 | elf.inputs.addOneAssumeCapacity().* = .{ |
| 2417 | .path = elf.base.emit, | 3478 | .path = elf.base.emit, |
| 2418 | .member = null, | 3479 | .member = null, |
| 2419 | .si = si, | 3480 | .file_symbol = zcu_file_symbol, |
| 2420 | }; | 3481 | }; |
| 2421 | | 3482 | |
| 2422 | if (elf.si.dynamic != .null) switch (elf.identClass()) { | 3483 | if (elf.shndx.dynamic != .UNDEF) switch (elf.identClass()) { |
| 2423 | .NONE, _ => unreachable, | 3484 | .NONE, _ => unreachable, |
| 2424 | inline else => |ct_class| { | 3485 | inline else => |ct_class| { |
| 2425 | const ElfN = ct_class.ElfN(); | 3486 | const ElfN = ct_class.ElfN(); |
| ... | @@ -2430,9 +3491,9 @@ fn prelinkInner(elf: *Elf) !void { | ... | @@ -2430,9 +3491,9 @@ fn prelinkInner(elf: *Elf) !void { |
| 2430 | @intFromBool(flags != 0) + @intFromBool(flags_1 != 0) + | 3491 | @intFromBool(flags != 0) + @intFromBool(flags_1 != 0) + |
| 2431 | @intFromBool(comp.config.output_mode == .Exe) + 12; | 3492 | @intFromBool(comp.config.output_mode == .Exe) + 12; |
| 2432 | const dynamic_size: u32 = @intCast(@sizeOf(ElfN.Addr) * 2 * dynamic_len); | 3493 | const dynamic_size: u32 = @intCast(@sizeOf(ElfN.Addr) * 2 * dynamic_len); |
| 2433 | const dynamic_ni = elf.si.dynamic.node(elf); | 3494 | const dynamic_ni = elf.shndx.dynamic.get(elf).ni; |
| 2434 | try dynamic_ni.resize(&elf.mf, gpa, dynamic_size); | 3495 | try dynamic_ni.resize(&elf.mf, gpa, dynamic_size); |
| 2435 | switch (elf.shdrPtr(elf.si.dynamic.shndx(elf))) { | 3496 | switch (elf.shdrPtr(elf.shndx.dynamic)) { |
| 2436 | inline else => |shdr| elf.targetStore(&shdr.size, dynamic_size), | 3497 | inline else => |shdr| elf.targetStore(&shdr.size, dynamic_size), |
| 2437 | } | 3498 | } |
| 2438 | const sec_dynamic = dynamic_ni.slice(&elf.mf); | 3499 | const sec_dynamic = dynamic_ni.slice(&elf.mf); |
| ... | @@ -2441,10 +3502,10 @@ fn prelinkInner(elf: *Elf) !void { | ... | @@ -2441,10 +3502,10 @@ fn prelinkInner(elf: *Elf) !void { |
| 2441 | for ( | 3502 | for ( |
| 2442 | dynamic_entries[dynamic_index..][0..needed_len], | 3503 | dynamic_entries[dynamic_index..][0..needed_len], |
| 2443 | elf.needed.keys(), | 3504 | elf.needed.keys(), |
| 2444 | ) |*dynamic_entry, needed| dynamic_entry.* = .{ std.elf.DT_NEEDED, needed }; | 3505 | ) |*dynamic_entry, needed| dynamic_entry.* = .{ std.elf.DT_NEEDED, @intFromEnum(needed) }; |
| 2445 | dynamic_index += needed_len; | 3506 | dynamic_index += needed_len; |
| 2446 | if (elf.options.soname) |soname| { | 3507 | if (elf.options.soname) |soname| { |
| 2447 | dynamic_entries[dynamic_index] = .{ std.elf.DT_SONAME, try elf.string(.dynstr, soname) }; | 3508 | dynamic_entries[dynamic_index] = .{ std.elf.DT_SONAME, @intFromEnum(try elf.string(.dynstr, soname)) }; |
| 2448 | dynamic_index += 1; | 3509 | dynamic_index += 1; |
| 2449 | } | 3510 | } |
| 2450 | if (flags != 0) { | 3511 | if (flags != 0) { |
| ... | @@ -2459,25 +3520,25 @@ fn prelinkInner(elf: *Elf) !void { | ... | @@ -2459,25 +3520,25 @@ fn prelinkInner(elf: *Elf) !void { |
| 2459 | dynamic_entries[dynamic_index] = .{ std.elf.DT_DEBUG, 0 }; | 3520 | dynamic_entries[dynamic_index] = .{ std.elf.DT_DEBUG, 0 }; |
| 2460 | dynamic_index += 1; | 3521 | dynamic_index += 1; |
| 2461 | } | 3522 | } |
| 2462 | const rela_dyn_si = elf.si.got.shndx(elf).get(elf).rela_si; | 3523 | const rela_dyn_shndx = elf.shndx.got.get(elf).rela_shndx; |
| 2463 | const rela_plt_si = elf.si.got_plt.shndx(elf).get(elf).rela_si; | 3524 | const rela_plt_shndx = elf.shndx.got_plt.get(elf).rela_shndx; |
| 2464 | dynamic_entries[dynamic_index..][0..12].* = .{ | 3525 | dynamic_entries[dynamic_index..][0..12].* = .{ |
| 2465 | .{ std.elf.DT_RELA, @intCast(elf.computeNodeVAddr(rela_dyn_si.node(elf))) }, | 3526 | .{ std.elf.DT_RELA, @intCast(elf.computeNodeVAddr(rela_dyn_shndx.get(elf).ni)) }, |
| 2466 | .{ std.elf.DT_RELASZ, elf.targetLoad( | 3527 | .{ std.elf.DT_RELASZ, elf.targetLoad( |
| 2467 | &@field(elf.shdrPtr(rela_dyn_si.shndx(elf)), @tagName(ct_class)).size, | 3528 | &@field(elf.shdrPtr(rela_dyn_shndx), @tagName(ct_class)).size, |
| 2468 | ) }, | 3529 | ) }, |
| 2469 | .{ std.elf.DT_RELAENT, @sizeOf(ElfN.Rela) }, | 3530 | .{ std.elf.DT_RELAENT, @sizeOf(ElfN.Rela) }, |
| 2470 | .{ std.elf.DT_JMPREL, @intCast(elf.computeNodeVAddr(rela_plt_si.node(elf))) }, | 3531 | .{ std.elf.DT_JMPREL, @intCast(elf.computeNodeVAddr(rela_plt_shndx.get(elf).ni)) }, |
| 2471 | .{ std.elf.DT_PLTRELSZ, elf.targetLoad( | 3532 | .{ std.elf.DT_PLTRELSZ, elf.targetLoad( |
| 2472 | &@field(elf.shdrPtr(rela_plt_si.shndx(elf)), @tagName(ct_class)).size, | 3533 | &@field(elf.shdrPtr(rela_plt_shndx), @tagName(ct_class)).size, |
| 2473 | ) }, | 3534 | ) }, |
| 2474 | .{ std.elf.DT_PLTGOT, @intCast(elf.computeNodeVAddr(elf.si.got_plt.node(elf))) }, | 3535 | .{ std.elf.DT_PLTGOT, @intCast(elf.computeNodeVAddr(elf.shndx.got_plt.get(elf).ni)) }, |
| 2475 | .{ std.elf.DT_PLTREL, std.elf.DT_RELA }, | 3536 | .{ std.elf.DT_PLTREL, std.elf.DT_RELA }, |
| 2476 | .{ std.elf.DT_SYMTAB, @intCast(elf.computeNodeVAddr(elf.si.dynsym.node(elf))) }, | 3537 | .{ std.elf.DT_SYMTAB, @intCast(elf.computeNodeVAddr(elf.shndx.dynsym.get(elf).ni)) }, |
| 2477 | .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) }, | 3538 | .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) }, |
| 2478 | .{ std.elf.DT_STRTAB, @intCast(elf.computeNodeVAddr(elf.si.dynstr.node(elf))) }, | 3539 | .{ std.elf.DT_STRTAB, @intCast(elf.computeNodeVAddr(elf.shndx.dynstr.get(elf).ni)) }, |
| 2479 | .{ std.elf.DT_STRSZ, elf.targetLoad( | 3540 | .{ std.elf.DT_STRSZ, elf.targetLoad( |
| 2480 | &@field(elf.shdrPtr(elf.si.dynstr.shndx(elf)), @tagName(ct_class)).size, | 3541 | &@field(elf.shdrPtr(elf.shndx.dynstr), @tagName(ct_class)).size, |
| 2481 | ) }, | 3542 | ) }, |
| 2482 | .{ std.elf.DT_NULL, 0 }, | 3543 | .{ std.elf.DT_NULL, 0 }, |
| 2483 | }; | 3544 | }; |
| ... | @@ -2486,42 +3547,40 @@ fn prelinkInner(elf: *Elf) !void { | ... | @@ -2486,42 +3547,40 @@ fn prelinkInner(elf: *Elf) !void { |
| 2486 | if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry| | 3547 | if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry| |
| 2487 | std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry); | 3548 | std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry); |
| 2488 | | 3549 | |
| 2489 | const dynamic_sym = elf.si.dynamic.get(elf); | 3550 | elf.first_dynamic_reloc = @enumFromInt(elf.relocs.items.len); |
| 2490 | assert(dynamic_sym.loc_relocs == .none); | 3551 | try elf.ensureUnusedRelocCapacity(dynamic_ni, 5); |
| 2491 | dynamic_sym.loc_relocs = @enumFromInt(elf.relocs.items.len); | | |
| 2492 | try elf.ensureUnusedRelocCapacity(elf.si.dynamic, 5); | | |
| 2493 | elf.addRelocAssumeCapacity( | 3552 | elf.addRelocAssumeCapacity( |
| 2494 | elf.si.dynamic, | 3553 | dynamic_ni, |
| 2495 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 12) + 1), | 3554 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 12) + 1), |
| 2496 | rela_dyn_si, | 3555 | .local(rela_dyn_shndx.get(elf).lsi), |
| 2497 | 0, | 3556 | 0, |
| 2498 | .absAddr(elf), | 3557 | .absAddr(elf), |
| 2499 | ); | 3558 | ); |
| 2500 | elf.addRelocAssumeCapacity( | 3559 | elf.addRelocAssumeCapacity( |
| 2501 | elf.si.dynamic, | 3560 | dynamic_ni, |
| 2502 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 9) + 1), | 3561 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 9) + 1), |
| 2503 | rela_plt_si, | 3562 | .local(rela_plt_shndx.get(elf).lsi), |
| 2504 | 0, | 3563 | 0, |
| 2505 | .absAddr(elf), | 3564 | .absAddr(elf), |
| 2506 | ); | 3565 | ); |
| 2507 | elf.addRelocAssumeCapacity( | 3566 | elf.addRelocAssumeCapacity( |
| 2508 | elf.si.dynamic, | 3567 | dynamic_ni, |
| 2509 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 7) + 1), | 3568 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 7) + 1), |
| 2510 | elf.si.got_plt, | 3569 | .local(elf.shndx.got_plt.get(elf).lsi), |
| 2511 | 0, | 3570 | 0, |
| 2512 | .absAddr(elf), | 3571 | .absAddr(elf), |
| 2513 | ); | 3572 | ); |
| 2514 | elf.addRelocAssumeCapacity( | 3573 | elf.addRelocAssumeCapacity( |
| 2515 | elf.si.dynamic, | 3574 | dynamic_ni, |
| 2516 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 5) + 1), | 3575 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 5) + 1), |
| 2517 | elf.si.dynsym, | 3576 | .local(elf.shndx.dynsym.get(elf).lsi), |
| 2518 | 0, | 3577 | 0, |
| 2519 | .absAddr(elf), | 3578 | .absAddr(elf), |
| 2520 | ); | 3579 | ); |
| 2521 | elf.addRelocAssumeCapacity( | 3580 | elf.addRelocAssumeCapacity( |
| 2522 | elf.si.dynamic, | 3581 | dynamic_ni, |
| 2523 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 3) + 1), | 3582 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 3) + 1), |
| 2524 | elf.si.dynstr, | 3583 | .local(elf.shndx.dynstr.get(elf).lsi), |
| 2525 | 0, | 3584 | 0, |
| 2526 | .absAddr(elf), | 3585 | .absAddr(elf), |
| 2527 | ); | 3586 | ); |
| ... | @@ -2529,36 +3588,6 @@ fn prelinkInner(elf: *Elf) !void { | ... | @@ -2529,36 +3588,6 @@ fn prelinkInner(elf: *Elf) !void { |
| 2529 | }; | 3588 | }; |
| 2530 | } | 3589 | } |
| 2531 | | 3590 | |
| 2532 | pub fn getNavVAddr( | | |
| 2533 | elf: *Elf, | | |
| 2534 | pt: Zcu.PerThread, | | |
| 2535 | nav: InternPool.Nav.Index, | | |
| 2536 | reloc_info: link.File.RelocInfo, | | |
| 2537 | ) !u64 { | | |
| 2538 | return elf.getVAddr(reloc_info, try elf.navSymbol(pt.zcu, nav)); | | |
| 2539 | } | | |
| 2540 | | | |
| 2541 | pub fn getUavVAddr( | | |
| 2542 | elf: *Elf, | | |
| 2543 | uav: InternPool.Index, | | |
| 2544 | reloc_info: link.File.RelocInfo, | | |
| 2545 | ) !u64 { | | |
| 2546 | return elf.getVAddr(reloc_info, try elf.uavSymbol(uav)); | | |
| 2547 | } | | |
| 2548 | | | |
| 2549 | pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.Index) !u64 { | | |
| 2550 | try elf.addReloc( | | |
| 2551 | @enumFromInt(reloc_info.parent.atom_index), | | |
| 2552 | reloc_info.offset, | | |
| 2553 | target_si, | | |
| 2554 | reloc_info.addend, | | |
| 2555 | .absAddr(elf), | | |
| 2556 | ); | | |
| 2557 | return switch (elf.symPtr(target_si)) { | | |
| 2558 | inline else => |sym| elf.targetLoad(&sym.value), | | |
| 2559 | }; | | |
| 2560 | } | | |
| 2561 | | | |
| 2562 | fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | 3591 | fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 2563 | name: []const u8 = "", | 3592 | name: []const u8 = "", |
| 2564 | type: std.elf.SHT = .NULL, | 3593 | type: std.elf.SHT = .NULL, |
| ... | @@ -2570,19 +3599,22 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | ... | @@ -2570,19 +3599,22 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 2570 | entsize: std.elf.Word = 0, | 3599 | entsize: std.elf.Word = 0, |
| 2571 | node_align: std.mem.Alignment = .@"1", | 3600 | node_align: std.mem.Alignment = .@"1", |
| 2572 | fixed: bool = false, | 3601 | fixed: bool = false, |
| 2573 | }) !Symbol.Index { | 3602 | }) !Section.Index { |
| 2574 | switch (opts.type) { | 3603 | switch (opts.type) { |
| 2575 | .NULL => assert(opts.size == 0), | 3604 | .NULL => assert(opts.size == 0), |
| 2576 | .PROGBITS => assert(opts.size > 0), | 3605 | .PROGBITS => assert(opts.size > 0), |
| 2577 | else => {}, | 3606 | else => {}, |
| 2578 | } | 3607 | } |
| | 3608 | if (opts.flags.ALLOC and elf.ehdrField(.type) != .REL) { |
| | 3609 | assert(elf.getNode(segment_ni) == .segment); |
| | 3610 | } |
| 2579 | const gpa = elf.base.comp.gpa; | 3611 | const gpa = elf.base.comp.gpa; |
| 2580 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | 3612 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 2581 | try elf.shdrs.ensureUnusedCapacity(gpa, 1); | 3613 | try elf.shdrs.ensureUnusedCapacity(gpa, 1); |
| 2582 | try elf.symtab.ensureUnusedCapacity(gpa, 1); | 3614 | if (opts.flags.ALLOC) try elf.ensureUnusedSymbolCapacity(1, .all_local); |
| 2583 | | 3615 | |
| 2584 | const shstrtab_entry = try elf.string(.shstrtab, opts.name); | 3616 | const shstrtab_entry = try elf.string(.shstrtab, opts.name); |
| 2585 | const shndx: Symbol.Index.Shndx, const new_shdr_size = shndx: switch (elf.ehdrPtr()) { | 3617 | const shndx: Section.Index, const new_shdr_size = shndx: switch (elf.ehdrPtr()) { |
| 2586 | inline else => |ehdr, class| { | 3618 | inline else => |ehdr, class| { |
| 2587 | const shndx, const shnum = alloc_shndx: switch (elf.targetLoad(&ehdr.shnum)) { | 3619 | const shndx, const shnum = alloc_shndx: switch (elf.targetLoad(&ehdr.shnum)) { |
| 2588 | 1...std.elf.SHN_LORESERVE - 2 => |shndx| { | 3620 | 1...std.elf.SHN_LORESERVE - 2 => |shndx| { |
| ... | @@ -2605,8 +3637,8 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | ... | @@ -2605,8 +3637,8 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 2605 | break :alloc_shndx .{ shndx, shnum }; | 3637 | break :alloc_shndx .{ shndx, shnum }; |
| 2606 | }, | 3638 | }, |
| 2607 | }; | 3639 | }; |
| 2608 | assert(shndx < @intFromEnum(Symbol.Index.Shndx.LORESERVE)); | 3640 | assert(shndx < @intFromEnum(Section.Index.LORESERVE)); |
| 2609 | break :shndx .{ @enumFromInt(shndx), elf.targetLoad(&ehdr.shentsize) * shnum }; | 3641 | break :shndx .{ @enumFromInt(shndx), @as(u64, elf.targetLoad(&ehdr.shentsize)) * @as(u64, shnum) }; |
| 2610 | }, | 3642 | }, |
| 2611 | }; | 3643 | }; |
| 2612 | _, const shdr_node_size = elf.ni.shdr.location(&elf.mf).resolve(&elf.mf); | 3644 | _, const shdr_node_size = elf.ni.shdr.location(&elf.mf).resolve(&elf.mf); |
| ... | @@ -2622,17 +3654,22 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | ... | @@ -2622,17 +3654,22 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 2622 | .fixed = opts.fixed, | 3654 | .fixed = opts.fixed, |
| 2623 | .resized = opts.size > 0, | 3655 | .resized = opts.size > 0, |
| 2624 | }); | 3656 | }); |
| 2625 | const si = elf.addSymbolAssumeCapacity(); | | |
| 2626 | elf.nodes.appendAssumeCapacity(.{ .section = si }); | | |
| 2627 | elf.shdrs.appendAssumeCapacity(.{ .si = si, .rela_si = .null, .rela_free = .none }); | | |
| 2628 | si.get(elf).ni = ni; | | |
| 2629 | const addr = elf.computeNodeVAddr(ni); | 3657 | const addr = elf.computeNodeVAddr(ni); |
| | 3658 | const lsi: Symbol.LocalIndex = if (opts.flags.ALLOC) elf.addLocalSymbolAssumeCapacity(.{ |
| | 3659 | .node = ni, |
| | 3660 | .name = .empty, |
| | 3661 | .value = addr, |
| | 3662 | .size = 0, |
| | 3663 | .type = .SECTION, |
| | 3664 | .shndx = shndx, |
| | 3665 | }) else .null; |
| | 3666 | elf.shdrs.appendAssumeCapacity(.{ .lsi = lsi, .ni = ni, .rela_shndx = .UNDEF, .rela_free = .none }); |
| | 3667 | elf.nodes.appendAssumeCapacity(.{ .section = shndx }); |
| 2630 | const offset = ni.fileLocation(&elf.mf, false).offset; | 3668 | const offset = ni.fileLocation(&elf.mf, false).offset; |
| 2631 | try si.init(elf, .{ .value = addr, .type = .SECTION, .shndx = shndx }); | | |
| 2632 | switch (elf.shdrPtr(shndx)) { | 3669 | switch (elf.shdrPtr(shndx)) { |
| 2633 | inline else => |shdr, class| { | 3670 | inline else => |shdr, class| { |
| 2634 | shdr.* = .{ | 3671 | shdr.* = .{ |
| 2635 | .name = shstrtab_entry, | 3672 | .name = @intFromEnum(shstrtab_entry), |
| 2636 | .type = opts.type, | 3673 | .type = opts.type, |
| 2637 | .flags = .{ .shf = opts.flags }, | 3674 | .flags = .{ .shf = opts.flags }, |
| 2638 | .addr = @intCast(addr), | 3675 | .addr = @intCast(addr), |
| ... | @@ -2646,63 +3683,31 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | ... | @@ -2646,63 +3683,31 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 2646 | if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(class.ElfN().Shdr, shdr); | 3683 | if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(class.ElfN().Shdr, shdr); |
| 2647 | }, | 3684 | }, |
| 2648 | } | 3685 | } |
| 2649 | return si; | 3686 | return shndx; |
| 2650 | } | | |
| 2651 | | | |
| 2652 | fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void { | | |
| 2653 | const shstrtab_entry = try elf.string(.shstrtab, name); | | |
| 2654 | switch (elf.shdrPtr(si.shndx(elf))) { | | |
| 2655 | inline else => |shdr| elf.targetStore(&shdr.name, shstrtab_entry), | | |
| 2656 | } | | |
| 2657 | } | | |
| 2658 | | | |
| 2659 | fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 { | | |
| 2660 | const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrPtr(si.shndx(elf))) { | | |
| 2661 | inline else => |shdr| elf.targetLoad(&shdr.name), | | |
| 2662 | }..]; | | |
| 2663 | return name[0..std.mem.indexOfScalar(u8, name, 0).? :0]; | | |
| 2664 | } | | |
| 2665 | | | |
| 2666 | fn string(elf: *Elf, comptime section: enum { shstrtab, strtab, dynstr }, key: []const u8) !u32 { | | |
| 2667 | if (key.len == 0) return 0; | | |
| 2668 | return @field(elf, @tagName(section)).get(elf, @field(elf.si, @tagName(section)), key); | | |
| 2669 | } | 3687 | } |
| 2670 | | 3688 | |
| 2671 | pub fn addReloc( | 3689 | fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize) !void { |
| 2672 | elf: *Elf, | | |
| 2673 | loc_si: Symbol.Index, | | |
| 2674 | offset: u64, | | |
| 2675 | target_si: Symbol.Index, | | |
| 2676 | addend: i64, | | |
| 2677 | @"type": Reloc.Type, | | |
| 2678 | ) !void { | | |
| 2679 | try elf.ensureUnusedRelocCapacity(loc_si, 1); | | |
| 2680 | elf.addRelocAssumeCapacity(loc_si, offset, target_si, addend, @"type"); | | |
| 2681 | } | | |
| 2682 | pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !void { | | |
| 2683 | if (len == 0) return; | 3690 | if (len == 0) return; |
| 2684 | const gpa = elf.base.comp.gpa; | 3691 | const gpa = elf.base.comp.gpa; |
| 2685 | try elf.relocs.ensureUnusedCapacity(gpa, len); | 3692 | try elf.relocs.ensureUnusedCapacity(gpa, len); |
| 2686 | const class = elf.identClass(); | 3693 | const class = elf.identClass(); |
| 2687 | const rela_si, const rela_len = rela: switch (elf.ehdrField(.type)) { | 3694 | const rela_shndx, const rela_len = rela: switch (elf.ehdrField(.type)) { |
| 2688 | .NONE, .CORE, _ => unreachable, | 3695 | .NONE, .CORE, _ => unreachable, |
| 2689 | .REL => { | 3696 | .REL => { |
| 2690 | const shndx = loc_si.shndx(elf); | 3697 | const shndx = elf.getNodeShndx(node); |
| 2691 | const sh = shndx.get(elf); | 3698 | if (shndx.get(elf).rela_shndx == .UNDEF) { |
| 2692 | if (sh.rela_si == .null) { | | |
| 2693 | var bfa_buf: [32]u8 = undefined; | 3699 | var bfa_buf: [32]u8 = undefined; |
| 2694 | var bfa: std.heap.BufferFirstAllocator = .init(&bfa_buf, gpa); | 3700 | var bfa: std.heap.BufferFirstAllocator = .init(&bfa_buf, gpa); |
| 2695 | const allocator = bfa.allocator(); | 3701 | const allocator = bfa.allocator(); |
| 2696 | | 3702 | |
| 2697 | const rela_name = | 3703 | const rela_name = try std.fmt.allocPrint(allocator, ".rela{s}", .{shndx.name(elf)}); |
| 2698 | try std.fmt.allocPrint(allocator, ".rela{s}", .{elf.sectionName(sh.si)}); | | |
| 2699 | defer allocator.free(rela_name); | 3704 | defer allocator.free(rela_name); |
| 2700 | | 3705 | |
| 2701 | sh.rela_si = try elf.addSection(.none, .{ | 3706 | const rela_shndx = try elf.addSection(.none, .{ |
| 2702 | .name = rela_name, | 3707 | .name = rela_name, |
| 2703 | .type = .RELA, | 3708 | .type = .RELA, |
| 2704 | .link = @intFromEnum(elf.si.symtab.shndx(elf)), | 3709 | .link = @intFromEnum(Section.Index.symtab), |
| 2705 | .info = @intFromEnum(shndx), | 3710 | .info = shndx.toSection().?, |
| 2706 | .addralign = switch (class) { | 3711 | .addralign = switch (class) { |
| 2707 | .NONE, _ => unreachable, | 3712 | .NONE, _ => unreachable, |
| 2708 | .@"32" => .@"4", | 3713 | .@"32" => .@"4", |
| ... | @@ -2714,14 +3719,15 @@ pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !v | ... | @@ -2714,14 +3719,15 @@ pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !v |
| 2714 | }, | 3719 | }, |
| 2715 | .node_align = elf.mf.flags.block_size, | 3720 | .node_align = elf.mf.flags.block_size, |
| 2716 | }); | 3721 | }); |
| | 3722 | shndx.get(elf).rela_shndx = rela_shndx; |
| 2717 | } | 3723 | } |
| 2718 | break :rela .{ sh.rela_si, len }; | 3724 | break :rela .{ shndx.get(elf).rela_shndx, len }; |
| 2719 | }, | 3725 | }, |
| 2720 | .EXEC, .DYN => switch (elf.got.tlsld) { | 3726 | .EXEC, .DYN => switch (elf.got.tlsld) { |
| 2721 | _ => return, | 3727 | _ => return, |
| 2722 | .none => if (elf.si.dynamic != .null) { | 3728 | .none => if (elf.shndx.dynamic != .UNDEF) { |
| 2723 | try elf.mf.updates.ensureUnusedCapacity(gpa, 1); | 3729 | try elf.mf.updates.ensureUnusedCapacity(gpa, 1); |
| 2724 | const got_ni = elf.si.got.node(elf); | 3730 | const got_ni = elf.shndx.got.get(elf).ni; |
| 2725 | _, const got_node_size = got_ni.location(&elf.mf).resolve(&elf.mf); | 3731 | _, const got_node_size = got_ni.location(&elf.mf).resolve(&elf.mf); |
| 2726 | const got_size = switch (class) { | 3732 | const got_size = switch (class) { |
| 2727 | .NONE, _ => unreachable, | 3733 | .NONE, _ => unreachable, |
| ... | @@ -2729,43 +3735,52 @@ pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !v | ... | @@ -2729,43 +3735,52 @@ pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !v |
| 2729 | }; | 3735 | }; |
| 2730 | if (got_size > got_node_size) | 3736 | if (got_size > got_node_size) |
| 2731 | try got_ni.resize(&elf.mf, gpa, got_size +| got_size / MappedFile.growth_factor); | 3737 | try got_ni.resize(&elf.mf, gpa, got_size +| got_size / MappedFile.growth_factor); |
| 2732 | break :rela .{ elf.si.got.shndx(elf).get(elf).rela_si, 1 }; | 3738 | break :rela .{ elf.shndx.got.get(elf).rela_shndx, 1 }; |
| 2733 | } else return, | 3739 | } else return, |
| 2734 | }, | 3740 | }, |
| 2735 | }; | 3741 | }; |
| 2736 | const rela_ni = rela_si.node(elf); | 3742 | const rela_ni = rela_shndx.get(elf).ni; |
| 2737 | _, const rela_node_size = rela_ni.location(&elf.mf).resolve(&elf.mf); | 3743 | _, const rela_node_size = rela_ni.location(&elf.mf).resolve(&elf.mf); |
| 2738 | const rela_size = switch (elf.shdrPtr(rela_si.shndx(elf))) { | 3744 | const rela_size = switch (elf.shdrPtr(rela_shndx)) { |
| 2739 | inline else => |shdr| elf.targetLoad(&shdr.size) + elf.targetLoad(&shdr.entsize) * rela_len, | 3745 | inline else => |shdr| elf.targetLoad(&shdr.size) + elf.targetLoad(&shdr.entsize) * rela_len, |
| 2740 | }; | 3746 | }; |
| 2741 | if (rela_size > rela_node_size) | 3747 | if (rela_size > rela_node_size) |
| 2742 | try rela_ni.resize(&elf.mf, gpa, rela_size +| rela_size / MappedFile.growth_factor); | 3748 | try rela_ni.resize(&elf.mf, gpa, rela_size +| rela_size / MappedFile.growth_factor); |
| 2743 | } | 3749 | } |
| 2744 | pub fn addRelocAssumeCapacity( | 3750 | fn addRelocAssumeCapacity( |
| 2745 | elf: *Elf, | 3751 | elf: *Elf, |
| 2746 | loc_si: Symbol.Index, | 3752 | node: MappedFile.Node.Index, |
| 2747 | offset: u64, | 3753 | offset: u64, |
| 2748 | target_si: Symbol.Index, | 3754 | target: Symbol.Id, |
| 2749 | addend: i64, | 3755 | addend: i64, |
| 2750 | @"type": Reloc.Type, | 3756 | @"type": Reloc.Type, |
| 2751 | ) void { | 3757 | ) void { |
| 2752 | const target = target_si.get(elf); | 3758 | assert(node != .none); |
| 2753 | const ri: Reloc.Index = @enumFromInt(elf.relocs.items.len); | 3759 | const ri: Reloc.Index = @enumFromInt(elf.relocs.items.len); |
| | 3760 | const next: Reloc.Index = next: { |
| | 3761 | const target_ptr = target.index(elf).ptr(elf); |
| | 3762 | const next = target_ptr.first_target_reloc; |
| | 3763 | target_ptr.first_target_reloc = ri; |
| | 3764 | break :next next; |
| | 3765 | }; |
| | 3766 | if (next != .none) { |
| | 3767 | next.get(elf).prev = ri; |
| | 3768 | } |
| 2754 | elf.relocs.addOneAssumeCapacity().* = .{ | 3769 | elf.relocs.addOneAssumeCapacity().* = .{ |
| 2755 | .type = @"type", | 3770 | .type = @"type", |
| 2756 | .prev = .none, | 3771 | .prev = .none, |
| 2757 | .next = target.target_relocs, | 3772 | .next = next, |
| 2758 | .loc = loc_si, | 3773 | .node = node, |
| 2759 | .target = target_si, | 3774 | .target = target, |
| 2760 | .index = index: switch (elf.ehdrField(.type)) { | 3775 | .index = index: switch (elf.ehdrField(.type)) { |
| 2761 | .NONE, .CORE, _ => unreachable, | 3776 | .NONE, .CORE, _ => unreachable, |
| 2762 | .REL => { | 3777 | .REL => { |
| 2763 | const sh = loc_si.shndx(elf).get(elf); | 3778 | const sh = elf.getNodeShndx(node).get(elf); |
| 2764 | switch (elf.shdrPtr(sh.rela_si.shndx(elf))) { | 3779 | switch (elf.shdrPtr(sh.rela_shndx)) { |
| 2765 | inline else => |shdr, class| { | 3780 | inline else => |shdr, class| { |
| 2766 | const Rela = class.ElfN().Rela; | 3781 | const Rela = class.ElfN().Rela; |
| 2767 | const ent_size = elf.targetLoad(&shdr.entsize); | 3782 | const ent_size = elf.targetLoad(&shdr.entsize); |
| 2768 | const rela_slice = sh.rela_si.node(elf).slice(&elf.mf); | 3783 | const rela_slice = sh.rela_shndx.get(elf).ni.slice(&elf.mf); |
| 2769 | const index: u32 = if (sh.rela_free.unwrap()) |index| alloc_index: { | 3784 | const index: u32 = if (sh.rela_free.unwrap()) |index| alloc_index: { |
| 2770 | const rela: *Rela = @ptrCast(@alignCast( | 3785 | const rela: *Rela = @ptrCast(@alignCast( |
| 2771 | rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)], | 3786 | rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)], |
| ... | @@ -2781,11 +3796,15 @@ pub fn addRelocAssumeCapacity( | ... | @@ -2781,11 +3796,15 @@ pub fn addRelocAssumeCapacity( |
| 2781 | const rela: *Rela = @ptrCast(@alignCast( | 3796 | const rela: *Rela = @ptrCast(@alignCast( |
| 2782 | rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)], | 3797 | rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)], |
| 2783 | )); | 3798 | )); |
| | 3799 | // The `offset` field here needs to equal the offset into the section, which |
| | 3800 | // is *not* the same as our `offset` which is the offset into `node`. We |
| | 3801 | // could calculate it now, but there's no point since `flushMovedNodeRelocs` |
| | 3802 | // will eventually do that for us anyway. So for now, just set offset to 0. |
| 2784 | rela.* = .{ | 3803 | rela.* = .{ |
| 2785 | .offset = @intCast(offset), | 3804 | .offset = 0, |
| 2786 | .info = .{ | 3805 | .info = .{ |
| 2787 | .type = @intCast(@"type".unwrap(elf)), | 3806 | .type = @intCast(@"type".unwrap(elf)), |
| 2788 | .sym = @intCast(@intFromEnum(target_si)), | 3807 | .sym = @intCast(@intFromEnum(target.index(elf))), |
| 2789 | }, | 3808 | }, |
| 2790 | .addend = @intCast(addend), | 3809 | .addend = @intCast(addend), |
| 2791 | }; | 3810 | }; |
| ... | @@ -2802,25 +3821,25 @@ pub fn addRelocAssumeCapacity( | ... | @@ -2802,25 +3821,25 @@ pub fn addRelocAssumeCapacity( |
| 2802 | else => {}, | 3821 | else => {}, |
| 2803 | .TLSLD => switch (elf.got.tlsld) { | 3822 | .TLSLD => switch (elf.got.tlsld) { |
| 2804 | _ => {}, | 3823 | _ => {}, |
| 2805 | .none => if (elf.si.dynamic != .null) { | 3824 | .none => if (elf.shndx.dynamic != .UNDEF) { |
| 2806 | const tlsld_index = elf.got.len; | 3825 | const tlsld_index = elf.got.len; |
| 2807 | elf.got.tlsld = .wrap(tlsld_index); | 3826 | elf.got.tlsld = .wrap(tlsld_index); |
| 2808 | elf.got.len = tlsld_index + 2; | 3827 | elf.got.len = tlsld_index + 2; |
| 2809 | const got_addr = got_addr: switch (elf.shdrPtr(elf.si.got.shndx(elf))) { | 3828 | const got_addr = got_addr: switch (elf.shdrPtr(elf.shndx.got)) { |
| 2810 | inline else => |shdr, class| { | 3829 | inline else => |shdr, class| { |
| 2811 | const addr_size = @sizeOf(class.ElfN().Addr); | 3830 | const addr_size = @sizeOf(class.ElfN().Addr); |
| 2812 | const old_size = addr_size * tlsld_index; | 3831 | const old_size = addr_size * tlsld_index; |
| 2813 | const new_size = old_size + addr_size * 2; | 3832 | const new_size = old_size + addr_size * 2; |
| 2814 | @memset( | 3833 | @memset( |
| 2815 | elf.si.got.node(elf).slice(&elf.mf)[old_size..new_size], | 3834 | elf.shndx.got.get(elf).ni.slice(&elf.mf)[old_size..new_size], |
| 2816 | 0, | 3835 | 0, |
| 2817 | ); | 3836 | ); |
| 2818 | break :got_addr elf.targetLoad(&shdr.addr) + old_size; | 3837 | break :got_addr elf.targetLoad(&shdr.addr) + old_size; |
| 2819 | }, | 3838 | }, |
| 2820 | }; | 3839 | }; |
| 2821 | const rela_dyn_si = elf.si.got.shndx(elf).get(elf).rela_si; | 3840 | const rela_dyn_shndx = elf.shndx.got.get(elf).rela_shndx; |
| 2822 | const rela_dyn_ni = rela_dyn_si.node(elf); | 3841 | const rela_dyn_ni = rela_dyn_shndx.get(elf).ni; |
| 2823 | switch (elf.shdrPtr(rela_dyn_si.shndx(elf))) { | 3842 | switch (elf.shdrPtr(rela_dyn_shndx)) { |
| 2824 | inline else => |shdr, class| { | 3843 | inline else => |shdr, class| { |
| 2825 | const Rela = class.ElfN().Rela; | 3844 | const Rela = class.ElfN().Rela; |
| 2826 | const old_size = elf.targetLoad(&shdr.size); | 3845 | const old_size = elf.targetLoad(&shdr.size); |
| ... | @@ -2851,11 +3870,6 @@ pub fn addRelocAssumeCapacity( | ... | @@ -2851,11 +3870,6 @@ pub fn addRelocAssumeCapacity( |
| 2851 | .offset = offset, | 3870 | .offset = offset, |
| 2852 | .addend = addend, | 3871 | .addend = addend, |
| 2853 | }; | 3872 | }; |
| 2854 | switch (target.target_relocs) { | | |
| 2855 | .none => {}, | | |
| 2856 | else => |target_ri| target_ri.get(elf).prev = ri, | | |
| 2857 | } | | |
| 2858 | target.target_relocs = ri; | | |
| 2859 | } | 3873 | } |
| 2860 | | 3874 | |
| 2861 | pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { | 3875 | pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { |
| ... | @@ -2877,30 +3891,12 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) | ... | @@ -2877,30 +3891,12 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) |
| 2877 | if (!Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) return; | 3891 | if (!Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) return; |
| 2878 | | 3892 | |
| 2879 | const nmi = try elf.navMapIndex(zcu, nav_index); | 3893 | const nmi = try elf.navMapIndex(zcu, nav_index); |
| 2880 | const si = nmi.symbol(elf); | 3894 | const ni = nmi.symbol(elf).index().ptr(elf).node; |
| 2881 | const ni = ni: { | 3895 | elf.resetNodeRelocs(ni); |
| 2882 | const sym = si.get(elf); | 3896 | |
| 2883 | switch (sym.ni) { | 3897 | // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be |
| 2884 | .none => { | 3898 | // called to apply the NAV's new relocations. |
| 2885 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | 3899 | try ni.moved(gpa, &elf.mf); |
| 2886 | const sec_si = elf.navSection(ip, nav.resolved.?); | | |
| 2887 | const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ | | |
| 2888 | .alignment = zcu.navAlignment(nav_index).toStdMem(), | | |
| 2889 | .moved = true, | | |
| 2890 | }); | | |
| 2891 | elf.nodes.appendAssumeCapacity(.{ .nav = nmi }); | | |
| 2892 | sym.ni = ni; | | |
| 2893 | switch (elf.symPtr(si)) { | | |
| 2894 | inline else => |sym_ptr, class| sym_ptr.shndx = | | |
| 2895 | @field(elf.symPtr(sec_si), @tagName(class)).shndx, | | |
| 2896 | } | | |
| 2897 | }, | | |
| 2898 | else => si.deleteLocationRelocs(elf), | | |
| 2899 | } | | |
| 2900 | assert(sym.loc_relocs == .none); | | |
| 2901 | sym.loc_relocs = @enumFromInt(elf.relocs.items.len); | | |
| 2902 | break :ni sym.ni; | | |
| 2903 | }; | | |
| 2904 | | 3900 | |
| 2905 | var nw: MappedFile.Node.Writer = undefined; | 3901 | var nw: MappedFile.Node.Writer = undefined; |
| 2906 | ni.writer(&elf.mf, gpa, &nw); | 3902 | ni.writer(&elf.mf, gpa, &nw); |
| ... | @@ -2911,54 +3907,14 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) | ... | @@ -2911,54 +3907,14 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) |
| 2911 | zcu.navSrcLoc(nav_index), | 3907 | zcu.navSrcLoc(nav_index), |
| 2912 | .fromInterned(nav.resolved.?.value), | 3908 | .fromInterned(nav.resolved.?.value), |
| 2913 | &nw.interface, | 3909 | &nw.interface, |
| 2914 | .{ .atom_index = @intFromEnum(si) }, | 3910 | .{ .atom_index = Node.toAtom(ni) }, |
| 2915 | ) catch |err| switch (err) { | 3911 | ) catch |err| switch (err) { |
| 2916 | error.WriteFailed => return error.OutOfMemory, | 3912 | error.WriteFailed => return error.OutOfMemory, |
| 2917 | else => |e| return e, | 3913 | else => |e| return e, |
| 2918 | }; | 3914 | }; |
| 2919 | switch (elf.symPtr(si)) { | 3915 | switch (elf.symPtr(nmi.symbol(elf).index())) { |
| 2920 | inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)), | 3916 | inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)), |
| 2921 | } | 3917 | } |
| 2922 | si.applyLocationRelocs(elf); | | |
| 2923 | } | | |
| 2924 | | | |
| 2925 | pub fn lowerUav( | | |
| 2926 | elf: *Elf, | | |
| 2927 | pt: Zcu.PerThread, | | |
| 2928 | uav_val: InternPool.Index, | | |
| 2929 | uav_align: InternPool.Alignment, | | |
| 2930 | src_loc: Zcu.LazySrcLoc, | | |
| 2931 | ) !codegen.SymbolResult { | | |
| 2932 | const zcu = pt.zcu; | | |
| 2933 | const gpa = zcu.gpa; | | |
| 2934 | | | |
| 2935 | try elf.pending_uavs.ensureUnusedCapacity(gpa, 1); | | |
| 2936 | const umi = elf.uavMapIndex(uav_val) catch |err| switch (err) { | | |
| 2937 | error.OutOfMemory => |e| return e, | | |
| 2938 | else => |e| return .{ .fail = try Zcu.ErrorMsg.create( | | |
| 2939 | gpa, | | |
| 2940 | src_loc, | | |
| 2941 | "linker failed to update constant: {s}", | | |
| 2942 | .{@errorName(e)}, | | |
| 2943 | ) }, | | |
| 2944 | }; | | |
| 2945 | const si = umi.symbol(elf); | | |
| 2946 | if (switch (si.get(elf).ni) { | | |
| 2947 | .none => true, | | |
| 2948 | else => |ni| uav_align.toStdMem().order(ni.alignment(&elf.mf)).compare(.gt), | | |
| 2949 | }) { | | |
| 2950 | const gop = elf.pending_uavs.getOrPutAssumeCapacity(umi); | | |
| 2951 | if (gop.found_existing) { | | |
| 2952 | gop.value_ptr.alignment = gop.value_ptr.alignment.max(uav_align); | | |
| 2953 | } else { | | |
| 2954 | gop.value_ptr.* = .{ | | |
| 2955 | .alignment = uav_align, | | |
| 2956 | .src_loc = src_loc, | | |
| 2957 | }; | | |
| 2958 | elf.const_prog_node.increaseEstimatedTotalItems(1); | | |
| 2959 | } | | |
| 2960 | } | | |
| 2961 | return .{ .sym_index = @intFromEnum(si) }; | | |
| 2962 | } | 3918 | } |
| 2963 | | 3919 | |
| 2964 | pub fn updateFunc( | 3920 | pub fn updateFunc( |
| ... | @@ -2993,42 +3949,13 @@ fn updateFuncInner( | ... | @@ -2993,42 +3949,13 @@ fn updateFuncInner( |
| 2993 | const nav = ip.getNav(func.owner_nav); | 3949 | const nav = ip.getNav(func.owner_nav); |
| 2994 | | 3950 | |
| 2995 | const nmi = try elf.navMapIndex(zcu, func.owner_nav); | 3951 | const nmi = try elf.navMapIndex(zcu, func.owner_nav); |
| 2996 | const si = nmi.symbol(elf); | 3952 | log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), nmi.symbol(elf) }); |
| 2997 | log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), si }); | 3953 | const ni = nmi.symbol(elf).index().ptr(elf).node; |
| 2998 | const ni = ni: { | 3954 | elf.resetNodeRelocs(ni); |
| 2999 | const sym = si.get(elf); | 3955 | |
| 3000 | switch (sym.ni) { | 3956 | // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be |
| 3001 | .none => { | 3957 | // called to apply the NAV's new relocations. |
| 3002 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | 3958 | try ni.moved(gpa, &elf.mf); |
| 3003 | const sec_si = elf.navSection(ip, nav.resolved.?); | | |
| 3004 | const mod = zcu.navFileScope(func.owner_nav).mod.?; | | |
| 3005 | const target = &mod.resolved_target.result; | | |
| 3006 | const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ | | |
| 3007 | .alignment = switch (nav.resolved.?.@"align") { | | |
| 3008 | .none => switch (mod.optimize_mode) { | | |
| 3009 | .Debug, | | |
| 3010 | .ReleaseSafe, | | |
| 3011 | .ReleaseFast, | | |
| 3012 | => target_util.defaultFunctionAlignment(target), | | |
| 3013 | .ReleaseSmall => target_util.minFunctionAlignment(target), | | |
| 3014 | }, | | |
| 3015 | else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), | | |
| 3016 | }.toStdMem(), | | |
| 3017 | .moved = true, | | |
| 3018 | }); | | |
| 3019 | elf.nodes.appendAssumeCapacity(.{ .nav = nmi }); | | |
| 3020 | sym.ni = ni; | | |
| 3021 | switch (elf.symPtr(si)) { | | |
| 3022 | inline else => |sym_ptr, class| sym_ptr.shndx = | | |
| 3023 | @field(elf.symPtr(sec_si), @tagName(class)).shndx, | | |
| 3024 | } | | |
| 3025 | }, | | |
| 3026 | else => si.deleteLocationRelocs(elf), | | |
| 3027 | } | | |
| 3028 | assert(sym.loc_relocs == .none); | | |
| 3029 | sym.loc_relocs = @enumFromInt(elf.relocs.items.len); | | |
| 3030 | break :ni sym.ni; | | |
| 3031 | }; | | |
| 3032 | | 3959 | |
| 3033 | var nw: MappedFile.Node.Writer = undefined; | 3960 | var nw: MappedFile.Node.Writer = undefined; |
| 3034 | ni.writer(&elf.mf, gpa, &nw); | 3961 | ni.writer(&elf.mf, gpa, &nw); |
| ... | @@ -3038,7 +3965,7 @@ fn updateFuncInner( | ... | @@ -3038,7 +3965,7 @@ fn updateFuncInner( |
| 3038 | pt, | 3965 | pt, |
| 3039 | zcu.navSrcLoc(func.owner_nav), | 3966 | zcu.navSrcLoc(func.owner_nav), |
| 3040 | func_index, | 3967 | func_index, |
| 3041 | @intFromEnum(si), | 3968 | Node.toAtom(ni), |
| 3042 | mir, | 3969 | mir, |
| 3043 | &nw.interface, | 3970 | &nw.interface, |
| 3044 | .none, | 3971 | .none, |
| ... | @@ -3046,10 +3973,9 @@ fn updateFuncInner( | ... | @@ -3046,10 +3973,9 @@ fn updateFuncInner( |
| 3046 | error.WriteFailed => return nw.err.?, | 3973 | error.WriteFailed => return nw.err.?, |
| 3047 | else => |e| return e, | 3974 | else => |e| return e, |
| 3048 | }; | 3975 | }; |
| 3049 | switch (elf.symPtr(si)) { | 3976 | switch (elf.symPtr(nmi.symbol(elf).index())) { |
| 3050 | inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)), | 3977 | inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)), |
| 3051 | } | 3978 | } |
| 3052 | si.applyLocationRelocs(elf); | | |
| 3053 | } | 3979 | } |
| 3054 | | 3980 | |
| 3055 | pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void { | 3981 | pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void { |
| ... | @@ -3072,7 +3998,42 @@ pub fn flush( | ... | @@ -3072,7 +3998,42 @@ pub fn flush( |
| 3072 | const comp = elf.base.comp; | 3998 | const comp = elf.base.comp; |
| 3073 | _ = arena; | 3999 | _ = arena; |
| 3074 | _ = prog_node; | 4000 | _ = prog_node; |
| | 4001 | |
| | 4002 | if (elf.ehdrField(.type) != .REL and |
| | 4003 | elf.shndx.dynamic == .UNDEF and |
| | 4004 | elf.globals.strong_undef.count() > 0) |
| | 4005 | { |
| | 4006 | for (elf.globals.strong_undef.keys()) |name| { |
| | 4007 | comp.link_diags.addError("undefined global symbol '{s}'", .{name.slice(elf)}); |
| | 4008 | } |
| | 4009 | return error.LinkFailure; |
| | 4010 | } |
| | 4011 | |
| 3075 | while (try elf.idle(tid)) {} | 4012 | while (try elf.idle(tid)) {} |
| | 4013 | |
| | 4014 | const entry_addr: u64 = entry: { |
| | 4015 | const sym_name_slice: []const u8 = name: switch (elf.options.entry) { |
| | 4016 | .default => switch (comp.config.output_mode) { |
| | 4017 | .Exe => continue :name .enabled, |
| | 4018 | .Lib, .Obj => continue :name .disabled, |
| | 4019 | }, |
| | 4020 | .disabled => break :entry 0, |
| | 4021 | .enabled => "_start", |
| | 4022 | .named => |named| named, |
| | 4023 | }; |
| | 4024 | const sym_name_strtab = elf.string(.strtab, sym_name_slice) catch |err| switch (err) { |
| | 4025 | error.Canceled => |e| return e, |
| | 4026 | else => |e| return comp.link_diags.fail("flush write failed: {t}", .{e}), |
| | 4027 | }; |
| | 4028 | const global = elf.globalByName(sym_name_strtab) orelse break :entry 0; |
| | 4029 | switch (elf.symPtr(global.symtab_index)) { |
| | 4030 | inline else => |sym| break :entry elf.targetLoad(&sym.value), |
| | 4031 | } |
| | 4032 | }; |
| | 4033 | switch (elf.ehdrPtr()) { |
| | 4034 | inline else => |ehdr| elf.targetStore(&ehdr.entry, @intCast(entry_addr)), |
| | 4035 | } |
| | 4036 | |
| 3076 | elf.mf.flush() catch |err| switch (err) { | 4037 | elf.mf.flush() catch |err| switch (err) { |
| 3077 | error.Canceled => |e| return e, | 4038 | error.Canceled => |e| return e, |
| 3078 | else => |e| return comp.link_diags.fail("flush write failed: {t}", .{e}), | 4039 | else => |e| return comp.link_diags.fail("flush write failed: {t}", .{e}), |
| ... | @@ -3082,15 +4043,10 @@ pub fn flush( | ... | @@ -3082,15 +4043,10 @@ pub fn flush( |
| 3082 | pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { | 4043 | pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 3083 | const comp = elf.base.comp; | 4044 | const comp = elf.base.comp; |
| 3084 | task: { | 4045 | task: { |
| 3085 | while (elf.pending_uavs.pop()) |pending_uav| { | 4046 | while (elf.pending_uavs.pop()) |umi| { |
| 3086 | const sub_prog_node = elf.idleProgNode(tid, elf.const_prog_node, .{ .uav = pending_uav.key }); | 4047 | const sub_prog_node = elf.idleProgNode(tid, elf.const_prog_node, .{ .uav = umi }); |
| 3087 | defer sub_prog_node.end(); | 4048 | defer sub_prog_node.end(); |
| 3088 | elf.flushUav( | 4049 | elf.flushUav(.{ .zcu = comp.zcu.?, .tid = tid }, umi) catch |err| switch (err) { |
| 3089 | .{ .zcu = comp.zcu.?, .tid = tid }, | | |
| 3090 | pending_uav.key, | | |
| 3091 | pending_uav.value.alignment, | | |
| 3092 | pending_uav.value.src_loc, | | |
| 3093 | ) catch |err| switch (err) { | | |
| 3094 | error.OutOfMemory => |e| return e, | 4050 | error.OutOfMemory => |e| return e, |
| 3095 | else => |e| return comp.link_diags.fail( | 4051 | else => |e| return comp.link_diags.fail( |
| 3096 | "linker failed to lower constant: {t}", | 4052 | "linker failed to lower constant: {t}", |
| ... | @@ -3127,9 +4083,9 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { | ... | @@ -3127,9 +4083,9 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 3127 | break :task; | 4083 | break :task; |
| 3128 | }; | 4084 | }; |
| 3129 | if (elf.input_section_pending_index < elf.input_sections.items.len) { | 4085 | if (elf.input_section_pending_index < elf.input_sections.items.len) { |
| 3130 | const isi: Node.InputSectionIndex = @enumFromInt(elf.input_section_pending_index); | 4086 | const isi: InputSection.Index = @enumFromInt(elf.input_section_pending_index); |
| 3131 | elf.input_section_pending_index += 1; | 4087 | elf.input_section_pending_index += 1; |
| 3132 | const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(isi.symbol(elf).node(elf))); | 4088 | const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(isi.node(elf))); |
| 3133 | defer sub_prog_node.end(); | 4089 | defer sub_prog_node.end(); |
| 3134 | elf.flushInputSection(isi) catch |err| switch (err) { | 4090 | elf.flushInputSection(isi) catch |err| switch (err) { |
| 3135 | else => |e| { | 4091 | else => |e| { |
| ... | @@ -3137,9 +4093,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { | ... | @@ -3137,9 +4093,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 3137 | return comp.link_diags.fail( | 4093 | return comp.link_diags.fail( |
| 3138 | "linker failed to read input section '{s}' from \"{f}{f}\": {t}", | 4094 | "linker failed to read input section '{s}' from \"{f}{f}\": {t}", |
| 3139 | .{ | 4095 | .{ |
| 3140 | elf.sectionName( | 4096 | elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf), |
| 3141 | elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section, | | |
| 3142 | ), | | |
| 3143 | ii.path(elf).fmtEscapeString(), | 4097 | ii.path(elf).fmtEscapeString(), |
| 3144 | fmtMemberString(ii.member(elf)), | 4098 | fmtMemberString(ii.member(elf)), |
| 3145 | e, | 4099 | e, |
| ... | @@ -3149,6 +4103,20 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { | ... | @@ -3149,6 +4103,20 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 3149 | }; | 4103 | }; |
| 3150 | break :task; | 4104 | break :task; |
| 3151 | } | 4105 | } |
| | 4106 | if (elf.changed_symtab_index.pop()) |kv| { |
| | 4107 | if (elf.ehdrField(.type) == .REL) { |
| | 4108 | const sub_prog_node = elf.mf.update_prog_node.start(kv.key.slice(elf), 0); |
| | 4109 | defer sub_prog_node.end(); |
| | 4110 | const sym = elf.globalByName(kv.key).?.symtab_index.ptr(elf); |
| | 4111 | var ri = sym.first_target_reloc; |
| | 4112 | while (ri != .none) { |
| | 4113 | const reloc = ri.get(elf); |
| | 4114 | reloc.updateTargetIndex(elf); |
| | 4115 | ri = reloc.next; |
| | 4116 | } |
| | 4117 | break :task; |
| | 4118 | } |
| | 4119 | } |
| 3152 | while (elf.mf.updates.pop()) |ni| { | 4120 | while (elf.mf.updates.pop()) |ni| { |
| 3153 | const clean_moved = ni.cleanMoved(&elf.mf); | 4121 | const clean_moved = ni.cleanMoved(&elf.mf); |
| 3154 | const clean_resized = ni.cleanResized(&elf.mf); | 4122 | const clean_resized = ni.cleanResized(&elf.mf); |
| ... | @@ -3161,9 +4129,10 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { | ... | @@ -3161,9 +4129,10 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 3161 | } else elf.mf.update_prog_node.completeOne(); | 4129 | } else elf.mf.update_prog_node.completeOne(); |
| 3162 | } | 4130 | } |
| 3163 | } | 4131 | } |
| 3164 | if (elf.pending_uavs.count() > 0) return true; | 4132 | if (elf.pending_uavs.items.len > 0) return true; |
| 3165 | for (&elf.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; | 4133 | for (&elf.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; |
| 3166 | if (elf.input_sections.items.len > elf.input_section_pending_index) return true; | 4134 | if (elf.input_sections.items.len > elf.input_section_pending_index) return true; |
| | 4135 | if (elf.changed_symtab_index.count() > 0) return true; |
| 3167 | if (elf.mf.updates.items.len > 0) return true; | 4136 | if (elf.mf.updates.items.len > 0) return true; |
| 3168 | return false; | 4137 | return false; |
| 3169 | } | 4138 | } |
| ... | @@ -3177,13 +4146,13 @@ fn idleProgNode( | ... | @@ -3177,13 +4146,13 @@ fn idleProgNode( |
| 3177 | var name: [std.Progress.Node.max_name_len]u8 = undefined; | 4146 | var name: [std.Progress.Node.max_name_len]u8 = undefined; |
| 3178 | return prog_node.start(name: switch (node) { | 4147 | return prog_node.start(name: switch (node) { |
| 3179 | else => |tag| @tagName(tag), | 4148 | else => |tag| @tagName(tag), |
| 3180 | .section => |si| elf.sectionName(si), | 4149 | .section => |shndx| shndx.name(elf), |
| 3181 | .input_section => |isi| { | 4150 | .input_section => |isi| { |
| 3182 | const ii = isi.input(elf); | 4151 | const ii = isi.input(elf); |
| 3183 | break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{ | 4152 | break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{ |
| 3184 | ii.path(elf).fmtEscapeString(), | 4153 | ii.path(elf).fmtEscapeString(), |
| 3185 | fmtMemberString(ii.member(elf)), | 4154 | fmtMemberString(ii.member(elf)), |
| 3186 | elf.sectionName(elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section), | 4155 | elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf), |
| 3187 | }) catch &name; | 4156 | }) catch &name; |
| 3188 | }, | 4157 | }, |
| 3189 | .nav => |nmi| { | 4158 | .nav => |nmi| { |
| ... | @@ -3200,59 +4169,43 @@ fn flushUav( | ... | @@ -3200,59 +4169,43 @@ fn flushUav( |
| 3200 | elf: *Elf, | 4169 | elf: *Elf, |
| 3201 | pt: Zcu.PerThread, | 4170 | pt: Zcu.PerThread, |
| 3202 | umi: Node.UavMapIndex, | 4171 | umi: Node.UavMapIndex, |
| 3203 | uav_align: InternPool.Alignment, | | |
| 3204 | src_loc: Zcu.LazySrcLoc, | | |
| 3205 | ) !void { | 4172 | ) !void { |
| | 4173 | const comp = elf.base.comp; |
| | 4174 | const gpa = comp.gpa; |
| 3206 | const zcu = pt.zcu; | 4175 | const zcu = pt.zcu; |
| 3207 | const gpa = zcu.gpa; | | |
| 3208 | | 4176 | |
| 3209 | const uav_val = umi.uavValue(elf); | 4177 | const uav_val = umi.uavValue(elf); |
| 3210 | const si = umi.symbol(elf); | 4178 | const ni = umi.symbol(elf).index().ptr(elf).node; |
| 3211 | const ni = ni: { | 4179 | elf.resetNodeRelocs(ni); |
| 3212 | const sym = si.get(elf); | | |
| 3213 | switch (sym.ni) { | | |
| 3214 | .none => { | | |
| 3215 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | | |
| 3216 | const sec_si = elf.si.data; | | |
| 3217 | const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ | | |
| 3218 | .alignment = uav_align.toStdMem(), | | |
| 3219 | .moved = true, | | |
| 3220 | }); | | |
| 3221 | elf.nodes.appendAssumeCapacity(.{ .uav = umi }); | | |
| 3222 | sym.ni = ni; | | |
| 3223 | switch (elf.symPtr(si)) { | | |
| 3224 | inline else => |sym_ptr, class| sym_ptr.shndx = | | |
| 3225 | @field(elf.symPtr(sec_si), @tagName(class)).shndx, | | |
| 3226 | } | | |
| 3227 | }, | | |
| 3228 | else => { | | |
| 3229 | if (sym.ni.alignment(&elf.mf).order(uav_align.toStdMem()).compare(.gte)) return; | | |
| 3230 | si.deleteLocationRelocs(elf); | | |
| 3231 | }, | | |
| 3232 | } | | |
| 3233 | assert(sym.loc_relocs == .none); | | |
| 3234 | sym.loc_relocs = @enumFromInt(elf.relocs.items.len); | | |
| 3235 | break :ni sym.ni; | | |
| 3236 | }; | | |
| 3237 | | 4180 | |
| 3238 | var nw: MappedFile.Node.Writer = undefined; | 4181 | var nw: MappedFile.Node.Writer = undefined; |
| 3239 | ni.writer(&elf.mf, gpa, &nw); | 4182 | ni.writer(&elf.mf, gpa, &nw); |
| 3240 | defer nw.deinit(); | 4183 | defer nw.deinit(); |
| | 4184 | // TODO: UAV lowering should never require source locations. |
| | 4185 | const dummy_src_loc: Zcu.LazySrcLoc = .{ |
| | 4186 | .base_node_inst = try zcu.intern_pool.trackZir(gpa, comp.io, pt.tid, .{ |
| | 4187 | .file = zcu.module_roots.get(zcu.std_mod).?.unwrap().?, |
| | 4188 | .inst = .main_struct_inst, |
| | 4189 | }), |
| | 4190 | .offset = .{ .byte_abs = 0 }, |
| | 4191 | }; |
| 3241 | codegen.generateSymbol( | 4192 | codegen.generateSymbol( |
| 3242 | &elf.base, | 4193 | &elf.base, |
| 3243 | pt, | 4194 | pt, |
| 3244 | src_loc, | 4195 | dummy_src_loc, |
| 3245 | .fromInterned(uav_val), | 4196 | .fromInterned(uav_val), |
| 3246 | &nw.interface, | 4197 | &nw.interface, |
| 3247 | .{ .atom_index = @intFromEnum(si) }, | 4198 | .{ .atom_index = Node.toAtom(ni) }, |
| 3248 | ) catch |err| switch (err) { | 4199 | ) catch |err| switch (err) { |
| 3249 | error.WriteFailed => return error.OutOfMemory, | 4200 | error.WriteFailed => return error.OutOfMemory, |
| 3250 | else => |e| return e, | 4201 | else => |e| return e, |
| 3251 | }; | 4202 | }; |
| 3252 | switch (elf.symPtr(si)) { | 4203 | switch (elf.symPtr(umi.symbol(elf).index())) { |
| 3253 | inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)), | 4204 | inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)), |
| 3254 | } | 4205 | } |
| 3255 | si.applyLocationRelocs(elf); | 4206 | // The UAV should already be considered to have moved, because it is created as moved and |
| | 4207 | // pending calls to `flushUav` always happen before pending calls to `flushMoved`. |
| | 4208 | assert(ni.hasMoved(&elf.mf)); |
| 3256 | } | 4209 | } |
| 3257 | | 4210 | |
| 3258 | fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { | 4211 | fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { |
| ... | @@ -3260,33 +4213,12 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { | ... | @@ -3260,33 +4213,12 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { |
| 3260 | const gpa = zcu.gpa; | 4213 | const gpa = zcu.gpa; |
| 3261 | | 4214 | |
| 3262 | const lazy = lmr.lazySymbol(elf); | 4215 | const lazy = lmr.lazySymbol(elf); |
| 3263 | const si = lmr.symbol(elf); | 4216 | const ni = lmr.symbol(elf).index().ptr(elf).node; |
| 3264 | const ni = ni: { | 4217 | elf.resetNodeRelocs(ni); |
| 3265 | const sym = si.get(elf); | 4218 | |
| 3266 | switch (sym.ni) { | 4219 | // Ensure the lazy node is marked as moved so that once we're done, `flushMoved` will eventually |
| 3267 | .none => { | 4220 | // be called to apply the lazy node's new relocations. |
| 3268 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | 4221 | try ni.moved(gpa, &elf.mf); |
| 3269 | const sec_si: Symbol.Index = switch (lazy.kind) { | | |
| 3270 | .code => .text, | | |
| 3271 | .const_data => .rodata, | | |
| 3272 | }; | | |
| 3273 | const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ .moved = true }); | | |
| 3274 | elf.nodes.appendAssumeCapacity(switch (lazy.kind) { | | |
| 3275 | .code => .{ .lazy_code = @enumFromInt(lmr.index) }, | | |
| 3276 | .const_data => .{ .lazy_const_data = @enumFromInt(lmr.index) }, | | |
| 3277 | }); | | |
| 3278 | sym.ni = ni; | | |
| 3279 | switch (elf.symPtr(si)) { | | |
| 3280 | inline else => |sym_ptr, class| sym_ptr.shndx = | | |
| 3281 | @field(elf.symPtr(sec_si), @tagName(class)).shndx, | | |
| 3282 | } | | |
| 3283 | }, | | |
| 3284 | else => si.deleteLocationRelocs(elf), | | |
| 3285 | } | | |
| 3286 | assert(sym.loc_relocs == .none); | | |
| 3287 | sym.loc_relocs = @enumFromInt(elf.relocs.items.len); | | |
| 3288 | break :ni sym.ni; | | |
| 3289 | }; | | |
| 3290 | | 4222 | |
| 3291 | var required_alignment: InternPool.Alignment = .none; | 4223 | var required_alignment: InternPool.Alignment = .none; |
| 3292 | var nw: MappedFile.Node.Writer = undefined; | 4224 | var nw: MappedFile.Node.Writer = undefined; |
| ... | @@ -3300,15 +4232,14 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { | ... | @@ -3300,15 +4232,14 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { |
| 3300 | &required_alignment, | 4232 | &required_alignment, |
| 3301 | &nw.interface, | 4233 | &nw.interface, |
| 3302 | .none, | 4234 | .none, |
| 3303 | .{ .atom_index = @intFromEnum(si) }, | 4235 | .{ .atom_index = Node.toAtom(ni) }, |
| 3304 | ); | 4236 | ); |
| 3305 | switch (elf.symPtr(si)) { | 4237 | switch (elf.symPtr(lmr.symbol(elf).index())) { |
| 3306 | inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)), | 4238 | inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)), |
| 3307 | } | 4239 | } |
| 3308 | si.applyLocationRelocs(elf); | | |
| 3309 | } | 4240 | } |
| 3310 | | 4241 | |
| 3311 | fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void { | 4242 | fn flushInputSection(elf: *Elf, isi: InputSection.Index) !void { |
| 3312 | const file_loc = isi.fileLocation(elf); | 4243 | const file_loc = isi.fileLocation(elf); |
| 3313 | if (file_loc.size == 0) return; | 4244 | if (file_loc.size == 0) return; |
| 3314 | const comp = elf.base.comp; | 4245 | const comp = elf.base.comp; |
| ... | @@ -3321,12 +4252,13 @@ fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void { | ... | @@ -3321,12 +4252,13 @@ fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void { |
| 3321 | var fr = file.reader(io, &.{}); | 4252 | var fr = file.reader(io, &.{}); |
| 3322 | try fr.seekTo(file_loc.offset); | 4253 | try fr.seekTo(file_loc.offset); |
| 3323 | var nw: MappedFile.Node.Writer = undefined; | 4254 | var nw: MappedFile.Node.Writer = undefined; |
| 3324 | const si = isi.symbol(elf); | 4255 | isi.node(elf).writer(&elf.mf, gpa, &nw); |
| 3325 | si.node(elf).writer(&elf.mf, gpa, &nw); | | |
| 3326 | defer nw.deinit(); | 4256 | defer nw.deinit(); |
| 3327 | if (try nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) != file_loc.size) | 4257 | if (try nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) != file_loc.size) |
| 3328 | return error.EndOfStream; | 4258 | return error.EndOfStream; |
| 3329 | si.applyLocationRelocs(elf); | 4259 | // The input section should already be considered to have moved, because it is created as moved |
| | 4260 | // and pending calls to `flushInputSection` always happen before pending calls to `flushMoved`. |
| | 4261 | assert(isi.node(elf).hasMoved(&elf.mf)); |
| 3330 | } | 4262 | } |
| 3331 | | 4263 | |
| 3332 | fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void { | 4264 | fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| ... | @@ -3349,7 +4281,7 @@ fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void { | ... | @@ -3349,7 +4281,7 @@ fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 3349 | var child_it = ni.children(&elf.mf); | 4281 | var child_it = ni.children(&elf.mf); |
| 3350 | while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni); | 4282 | while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni); |
| 3351 | }, | 4283 | }, |
| 3352 | .section => |si| switch (elf.shdrPtr(si.shndx(elf))) { | 4284 | .section => |shndx| switch (elf.shdrPtr(shndx)) { |
| 3353 | inline else => |shdr| elf.targetStore(&shdr.offset, @intCast( | 4285 | inline else => |shdr| elf.targetStore(&shdr.offset, @intCast( |
| 3354 | ni.fileLocation(&elf.mf, false).offset, | 4286 | ni.fileLocation(&elf.mf, false).offset, |
| 3355 | )), | 4287 | )), |
| ... | @@ -3378,22 +4310,21 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { | ... | @@ -3378,22 +4310,21 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 3378 | }, | 4310 | }, |
| 3379 | } | 4311 | } |
| 3380 | }, | 4312 | }, |
| 3381 | .section => |si| { | 4313 | .section => |shndx| { |
| 3382 | try elf.flushFileOffset(ni); | 4314 | try elf.flushFileOffset(ni); |
| 3383 | const addr = elf.computeNodeVAddr(ni); | 4315 | const addr = elf.computeNodeVAddr(ni); |
| 3384 | const shndx = si.shndx(elf); | | |
| 3385 | switch (elf.shdrPtr(shndx)) { | 4316 | switch (elf.shdrPtr(shndx)) { |
| 3386 | inline else => |shdr, class| { | 4317 | inline else => |shdr, class| { |
| 3387 | const flags = elf.targetLoad(&shdr.flags).shf; | 4318 | const flags = elf.targetLoad(&shdr.flags).shf; |
| 3388 | if (flags.ALLOC) { | 4319 | if (flags.ALLOC) { |
| 3389 | if (elf.si.dynamic != .null) { | 4320 | if (elf.shndx.dynamic != .UNDEF) { |
| 3390 | if (si == elf.si.got) { | 4321 | if (shndx == elf.shndx.got) { |
| 3391 | const old_addr = elf.targetLoad(&shdr.addr); | 4322 | const old_addr = elf.targetLoad(&shdr.addr); |
| 3392 | const rela_dyn_si = shndx.get(elf).rela_si; | 4323 | const rela_dyn_shndx = shndx.get(elf).rela_shndx; |
| 3393 | const relas: []class.ElfN().Rela = @ptrCast(@alignCast( | 4324 | const relas: []class.ElfN().Rela = @ptrCast(@alignCast( |
| 3394 | rela_dyn_si.node(elf).slice(&elf.mf)[0..@intCast( | 4325 | rela_dyn_shndx.get(elf).ni.slice(&elf.mf)[0..@intCast( |
| 3395 | elf.targetLoad(&@field( | 4326 | elf.targetLoad(&@field( |
| 3396 | elf.shdrPtr(rela_dyn_si.shndx(elf)), | 4327 | elf.shdrPtr(rela_dyn_shndx), |
| 3397 | @tagName(class), | 4328 | @tagName(class), |
| 3398 | ).size), | 4329 | ).size), |
| 3399 | )], | 4330 | )], |
| ... | @@ -3413,19 +4344,19 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { | ... | @@ -3413,19 +4344,19 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 3413 | ), | 4344 | ), |
| 3414 | }, | 4345 | }, |
| 3415 | } | 4346 | } |
| 3416 | } else if (si == elf.si.got_plt) { | 4347 | } else if (shndx == elf.shndx.got_plt) { |
| 3417 | const target_endian = elf.targetEndian(); | 4348 | const target_endian = elf.targetEndian(); |
| 3418 | const old_addr = elf.targetLoad(&shdr.addr); | 4349 | const old_addr = elf.targetLoad(&shdr.addr); |
| 3419 | const rela_plt_si = shndx.get(elf).rela_si; | 4350 | const rela_plt_shndx = shndx.get(elf).rela_shndx; |
| 3420 | const relas: []class.ElfN().Rela = @ptrCast(@alignCast( | 4351 | const relas: []class.ElfN().Rela = @ptrCast(@alignCast( |
| 3421 | rela_plt_si.node(elf).slice(&elf.mf)[0..@intCast( | 4352 | rela_plt_shndx.get(elf).ni.slice(&elf.mf)[0..@intCast( |
| 3422 | elf.targetLoad(&@field( | 4353 | elf.targetLoad(&@field( |
| 3423 | elf.shdrPtr(rela_plt_si.shndx(elf)), | 4354 | elf.shdrPtr(rela_plt_shndx), |
| 3424 | @tagName(class), | 4355 | @tagName(class), |
| 3425 | ).size), | 4356 | ).size), |
| 3426 | )], | 4357 | )], |
| 3427 | )); | 4358 | )); |
| 3428 | const plt_sec_slice = elf.si.plt_sec.node(elf).slice(&elf.mf); | 4359 | const plt_sec_slice = elf.shndx.plt_sec.get(elf).ni.slice(&elf.mf); |
| 3429 | switch (elf.ehdrField(.machine)) { | 4360 | switch (elf.ehdrField(.machine)) { |
| 3430 | else => |machine| @panic(@tagName(machine)), | 4361 | else => |machine| @panic(@tagName(machine)), |
| 3431 | .AARCH64, .PPC64, .RISCV => {}, | 4362 | .AARCH64, .PPC64, .RISCV => {}, |
| ... | @@ -3454,7 +4385,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { | ... | @@ -3454,7 +4385,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 3454 | } | 4385 | } |
| 3455 | }, | 4386 | }, |
| 3456 | } | 4387 | } |
| 3457 | } else if (si == elf.si.plt_sec) { | 4388 | } else if (shndx == elf.shndx.plt_sec) { |
| 3458 | const target_endian = elf.targetEndian(); | 4389 | const target_endian = elf.targetEndian(); |
| 3459 | const old_addr = elf.targetLoad(&shdr.addr); | 4390 | const old_addr = elf.targetLoad(&shdr.addr); |
| 3460 | const plt_sec_slice = ni.slice(&elf.mf); | 4391 | const plt_sec_slice = ni.slice(&elf.mf); |
| ... | @@ -3477,34 +4408,72 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { | ... | @@ -3477,34 +4408,72 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 3477 | } | 4408 | } |
| 3478 | } | 4409 | } |
| 3479 | elf.targetStore(&shdr.addr, @intCast(addr)); | 4410 | elf.targetStore(&shdr.addr, @intCast(addr)); |
| 3480 | @field(elf.symPtr(si), @tagName(class)).value = shdr.addr; | 4411 | shndx.get(elf).lsi.index().flushMoved(elf, addr); |
| | 4412 | } |
| | 4413 | |
| | 4414 | if (shndx == elf.shndx.plt) { |
| | 4415 | elf.flushMovedNodeRelocs(ni, elf.targetLoad(&shdr.addr), elf.first_plt_reloc); |
| | 4416 | } else if (shndx == elf.shndx.dynamic) { |
| | 4417 | elf.flushMovedNodeRelocs(ni, elf.targetLoad(&shdr.addr), elf.first_dynamic_reloc); |
| 3481 | } | 4418 | } |
| 3482 | }, | 4419 | }, |
| 3483 | } | 4420 | } |
| 3484 | si.flushMoved(elf, addr); | | |
| 3485 | }, | 4421 | }, |
| 3486 | .input_section => |isi| { | 4422 | .input_section => |isi| { |
| 3487 | const old_addr = switch (elf.symPtr(isi.symbol(elf))) { | 4423 | const old_section_addr = isi.ptr(elf).vaddr; |
| 3488 | inline else => |sym| elf.targetLoad(&sym.value), | 4424 | const new_section_addr = elf.computeNodeVAddr(ni); |
| 3489 | }; | 4425 | isi.ptr(elf).vaddr = new_section_addr; |
| 3490 | const new_addr = elf.computeNodeVAddr(ni); | 4426 | |
| | 4427 | // Update local symbols |
| 3491 | const ii = isi.input(elf); | 4428 | const ii = isi.input(elf); |
| 3492 | var si = ii.symbol(elf); | 4429 | var lsi, const end_lsi = ii.localSymbolRange(elf); |
| 3493 | const end_si = ii.endSymbol(elf); | 4430 | while (lsi != end_lsi) : (lsi = @enumFromInt(@intFromEnum(lsi) + 1)) { |
| 3494 | while (cond: { | 4431 | if (lsi.index().ptr(elf).node != ni) continue; |
| 3495 | si = si.next(); | 4432 | const old_sym_addr: u64 = switch (elf.symPtr(lsi.index())) { |
| 3496 | break :cond si != end_si; | 4433 | inline else => |sym| switch (elf.targetLoad(&sym.other).visibility) { |
| 3497 | }) { | 4434 | .HIDDEN, .INTERNAL => { |
| 3498 | if (si.get(elf).ni != ni) continue; | 4435 | // This is actually a global symbol which got demoted to STB_LOCAL due |
| 3499 | si.flushMoved(elf, switch (elf.symPtr(si)) { | 4436 | // to its visibility. It will be handled in the global symbols pass |
| 3500 | inline else => |sym| elf.targetLoad(&sym.value), | 4437 | // below; don't touch it now. |
| 3501 | } - old_addr + new_addr); | 4438 | continue; |
| | 4439 | }, |
| | 4440 | .PROTECTED => unreachable, // not allowed for an STB_LOCAL symbol |
| | 4441 | .DEFAULT => elf.targetLoad(&sym.value), |
| | 4442 | }, |
| | 4443 | }; |
| | 4444 | lsi.index().flushMoved(elf, old_sym_addr - old_section_addr + new_section_addr); |
| | 4445 | } |
| | 4446 | |
| | 4447 | // Update global symbols |
| | 4448 | if (elf.node_global_symbols.get(ni)) |first_name| { |
| | 4449 | assert(first_name != .empty); |
| | 4450 | var name = first_name; |
| | 4451 | while (name != .empty) { |
| | 4452 | const global = elf.globalByName(name).?; |
| | 4453 | const old_sym_addr: u64 = switch (elf.symPtr(global.symtab_index)) { |
| | 4454 | inline else => |sym| elf.targetLoad(&sym.value), |
| | 4455 | }; |
| | 4456 | global.flushMoved(elf, old_sym_addr - old_section_addr + new_section_addr); |
| | 4457 | name = global.next_in_node; |
| | 4458 | } |
| 3502 | } | 4459 | } |
| | 4460 | |
| | 4461 | elf.flushMovedNodeRelocs(ni, new_section_addr, isi.ptrConst(elf).first_reloc); |
| | 4462 | }, |
| | 4463 | inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| { |
| | 4464 | const new_addr = elf.computeNodeVAddr(ni); |
| | 4465 | mi.symbol(elf).index().flushMoved(elf, new_addr); |
| | 4466 | if (elf.node_global_symbols.get(ni)) |first_name| { |
| | 4467 | assert(first_name != .empty); |
| | 4468 | var name = first_name; |
| | 4469 | while (name != .empty) { |
| | 4470 | const global = elf.globalByName(name).?; |
| | 4471 | global.flushMoved(elf, new_addr); |
| | 4472 | name = global.next_in_node; |
| | 4473 | } |
| | 4474 | } |
| | 4475 | elf.flushMovedNodeRelocs(ni, new_addr, mi.firstReloc(elf)); |
| 3503 | }, | 4476 | }, |
| 3504 | inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf).flushMoved( | | |
| 3505 | elf, | | |
| 3506 | elf.computeNodeVAddr(ni), | | |
| 3507 | ), | | |
| 3508 | } | 4477 | } |
| 3509 | try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); | 4478 | try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); |
| 3510 | } | 4479 | } |
| ... | @@ -3542,7 +4511,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { | ... | @@ -3542,7 +4511,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 3542 | switch (elf.targetLoad(&next_ph.type)) { | 4511 | switch (elf.targetLoad(&next_ph.type)) { |
| 3543 | else => unreachable, | 4512 | else => unreachable, |
| 3544 | .NULL, .LOAD => {}, | 4513 | .NULL, .LOAD => {}, |
| 3545 | .DYNAMIC, .INTERP, .PHDR, .TLS => break, | 4514 | .DYNAMIC, .INTERP, .PHDR, .TLS, std.elf.PT.GNU_RELRO => break, |
| 3546 | } | 4515 | } |
| 3547 | const next_vaddr = elf.targetLoad(&next_ph.vaddr); | 4516 | const next_vaddr = elf.targetLoad(&next_ph.vaddr); |
| 3548 | if (vaddr + memsz <= next_vaddr) break; | 4517 | if (vaddr + memsz <= next_vaddr) break; |
| ... | @@ -3564,7 +4533,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { | ... | @@ -3564,7 +4533,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 3564 | } | 4533 | } |
| 3565 | }, | 4534 | }, |
| 3566 | }, | 4535 | }, |
| 3567 | .section => |si| switch (elf.shdrPtr(si.shndx(elf))) { | 4536 | .section => |shndx| switch (elf.shdrPtr(shndx)) { |
| 3568 | inline else => |shdr, class| { | 4537 | inline else => |shdr, class| { |
| 3569 | switch (elf.targetLoad(&shdr.type)) { | 4538 | switch (elf.targetLoad(&shdr.type)) { |
| 3570 | else => unreachable, | 4539 | else => unreachable, |
| ... | @@ -3572,10 +4541,10 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { | ... | @@ -3572,10 +4541,10 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 3572 | .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL), | 4541 | .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL), |
| 3573 | .SYMTAB, .DYNAMIC, .REL, .DYNSYM => return, | 4542 | .SYMTAB, .DYNAMIC, .REL, .DYNSYM => return, |
| 3574 | .STRTAB => { | 4543 | .STRTAB => { |
| 3575 | if (elf.si.dynamic != .null) { | 4544 | if (elf.shndx.dynamic != .UNDEF) { |
| 3576 | if (si == elf.si.dynstr) { | 4545 | if (shndx == elf.shndx.dynstr) { |
| 3577 | const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast( | 4546 | const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast( |
| 3578 | elf.si.dynamic.node(elf).slice(&elf.mf), | 4547 | elf.shndx.dynamic.get(elf).ni.slice(&elf.mf), |
| 3579 | )); | 4548 | )); |
| 3580 | for (dynamic_entries) |*dynamic_entry| | 4549 | for (dynamic_entries) |*dynamic_entry| |
| 3581 | switch (elf.targetLoad(&dynamic_entry[0])) { | 4550 | switch (elf.targetLoad(&dynamic_entry[0])) { |
| ... | @@ -3587,19 +4556,19 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { | ... | @@ -3587,19 +4556,19 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 3587 | return; | 4556 | return; |
| 3588 | }, | 4557 | }, |
| 3589 | .RELA => { | 4558 | .RELA => { |
| 3590 | if (elf.si.dynamic != .null) { | 4559 | if (elf.shndx.dynamic != .UNDEF) { |
| 3591 | if (si == elf.si.got.shndx(elf).get(elf).rela_si) { | 4560 | if (shndx == elf.shndx.got.get(elf).rela_shndx) { |
| 3592 | const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast( | 4561 | const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast( |
| 3593 | elf.si.dynamic.node(elf).slice(&elf.mf), | 4562 | elf.shndx.dynamic.get(elf).ni.slice(&elf.mf), |
| 3594 | )); | 4563 | )); |
| 3595 | for (dynamic_entries) |*dynamic_entry| | 4564 | for (dynamic_entries) |*dynamic_entry| |
| 3596 | switch (elf.targetLoad(&dynamic_entry[0])) { | 4565 | switch (elf.targetLoad(&dynamic_entry[0])) { |
| 3597 | else => {}, | 4566 | else => {}, |
| 3598 | std.elf.DT_RELASZ => dynamic_entry[1] = shdr.size, | 4567 | std.elf.DT_RELASZ => dynamic_entry[1] = shdr.size, |
| 3599 | }; | 4568 | }; |
| 3600 | } else if (si == elf.si.got_plt.shndx(elf).get(elf).rela_si) { | 4569 | } else if (shndx == elf.shndx.got_plt.get(elf).rela_shndx) { |
| 3601 | const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast( | 4570 | const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast( |
| 3602 | elf.si.dynamic.node(elf).slice(&elf.mf), | 4571 | elf.shndx.dynamic.get(elf).ni.slice(&elf.mf), |
| 3603 | )); | 4572 | )); |
| 3604 | for (dynamic_entries) |*dynamic_entry| | 4573 | for (dynamic_entries) |*dynamic_entry| |
| 3605 | switch (elf.targetLoad(&dynamic_entry[0])) { | 4574 | switch (elf.targetLoad(&dynamic_entry[0])) { |
| ... | @@ -3611,7 +4580,9 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { | ... | @@ -3611,7 +4580,9 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 3611 | return; | 4580 | return; |
| 3612 | }, | 4581 | }, |
| 3613 | } | 4582 | } |
| 3614 | elf.targetStore(&shdr.size, @intCast(size)); | 4583 | if (shndx != elf.shndx.plt) { |
| | 4584 | elf.targetStore(&shdr.size, @intCast(size)); |
| | 4585 | } |
| 3615 | }, | 4586 | }, |
| 3616 | }, | 4587 | }, |
| 3617 | .input_section, .nav, .uav, .lazy_code, .lazy_const_data => {}, | 4588 | .input_section, .nav, .uav, .lazy_code, .lazy_const_data => {}, |
| ... | @@ -3642,7 +4613,6 @@ fn updateExportsInner( | ... | @@ -3642,7 +4613,6 @@ fn updateExportsInner( |
| 3642 | export_indices: []const Zcu.Export.Index, | 4613 | export_indices: []const Zcu.Export.Index, |
| 3643 | ) !void { | 4614 | ) !void { |
| 3644 | const zcu = pt.zcu; | 4615 | const zcu = pt.zcu; |
| 3645 | const gpa = zcu.gpa; | | |
| 3646 | const ip = &zcu.intern_pool; | 4616 | const ip = &zcu.intern_pool; |
| 3647 | | 4617 | |
| 3648 | switch (exported) { | 4618 | switch (exported) { |
| ... | @@ -3652,44 +4622,35 @@ fn updateExportsInner( | ... | @@ -3652,44 +4622,35 @@ fn updateExportsInner( |
| 3652 | Value.fromInterned(uav).fmtValue(pt), | 4622 | Value.fromInterned(uav).fmtValue(pt), |
| 3653 | }), | 4623 | }), |
| 3654 | } | 4624 | } |
| 3655 | try elf.symtab.ensureUnusedCapacity(gpa, export_indices.len); | 4625 | try elf.ensureUnusedSymbolCapacity(@intCast(export_indices.len), .maybe_global); |
| 3656 | const exported_si: Symbol.Index, const @"type": std.elf.STT = switch (exported) { | 4626 | const exported_lsi: Symbol.LocalIndex, const @"type": std.elf.STT = switch (exported) { |
| 3657 | .nav => |nav| .{ | 4627 | .nav => |nav| .{ |
| 3658 | try elf.navSymbol(zcu, nav), | 4628 | (try elf.navMapIndex(zcu, nav)).symbol(elf), |
| 3659 | navType(ip, ip.getNav(nav).resolved.?, elf.base.comp.config.any_non_single_threaded), | 4629 | navType(ip, ip.getNav(nav).resolved.?, elf.base.comp.config.any_non_single_threaded), |
| 3660 | }, | 4630 | }, |
| 3661 | .uav => |uav| .{ @enumFromInt(switch (try elf.lowerUav( | 4631 | .uav => |uav| .{ (try elf.uavMapIndex(uav, .none)).symbol(elf), .OBJECT }, |
| 3662 | pt, | | |
| 3663 | uav, | | |
| 3664 | Type.fromInterned(ip.typeOf(uav)).abiAlignment(zcu), | | |
| 3665 | export_indices[0].ptr(zcu).src, | | |
| 3666 | )) { | | |
| 3667 | .sym_index => |si| si, | | |
| 3668 | .fail => |em| { | | |
| 3669 | defer em.destroy(gpa); | | |
| 3670 | return elf.base.comp.link_diags.fail("{s}", .{em.msg}); | | |
| 3671 | }, | | |
| 3672 | }), .OBJECT }, | | |
| 3673 | }; | 4632 | }; |
| 3674 | while (try elf.idle(pt.tid)) {} | 4633 | while (try elf.idle(pt.tid)) {} |
| 3675 | const exported_ni = exported_si.node(elf); | 4634 | const value: u64, const size: u64, const shndx: Section.Index = switch (elf.symPtr(exported_lsi.index())) { |
| 3676 | const value, const size, const shndx = switch (elf.symPtr(exported_si)) { | | |
| 3677 | inline else => |exported_sym| .{ | 4635 | inline else => |exported_sym| .{ |
| 3678 | elf.targetLoad(&exported_sym.value), | 4636 | elf.targetLoad(&exported_sym.value), |
| 3679 | exported_sym.size, | 4637 | elf.targetLoad(&exported_sym.size), |
| 3680 | exported_sym.shndx, | 4638 | .fromSection(elf.targetLoad(&exported_sym.shndx)), |
| 3681 | }, | 4639 | }, |
| 3682 | }; | 4640 | }; |
| 3683 | for (export_indices) |export_index| { | 4641 | for (export_indices) |export_index| { |
| 3684 | const @"export" = export_index.ptr(zcu); | 4642 | const @"export" = export_index.ptr(zcu); |
| 3685 | const name = @"export".opts.name.toSlice(ip); | 4643 | const name = @"export".opts.name.toSlice(ip); |
| 3686 | const export_si = try elf.globalSymbol(.{ | 4644 | _ = elf.addGlobalSymbolAssumeCapacity(.{ |
| 3687 | .name = name, | 4645 | .node = .none, |
| | 4646 | .name = try .string(elf, name), |
| | 4647 | .value = value, |
| | 4648 | .size = @intCast(size), |
| 3688 | .type = @"type", | 4649 | .type = @"type", |
| 3689 | .bind = switch (@"export".opts.linkage) { | 4650 | .bind = switch (@"export".opts.linkage) { |
| 3690 | .internal => .LOCAL, | 4651 | .internal => @panic("TODO internal linkage"), |
| 3691 | .strong => .GLOBAL, | 4652 | .strong => .strong, |
| 3692 | .weak => .WEAK, | 4653 | .weak => .weak, |
| 3693 | .link_once => return error.LinkOnceUnsupported, | 4654 | .link_once => return error.LinkOnceUnsupported, |
| 3694 | }, | 4655 | }, |
| 3695 | .visibility = switch (@"export".opts.visibility) { | 4656 | .visibility = switch (@"export".opts.visibility) { |
| ... | @@ -3697,15 +4658,23 @@ fn updateExportsInner( | ... | @@ -3697,15 +4658,23 @@ fn updateExportsInner( |
| 3697 | .hidden => .HIDDEN, | 4658 | .hidden => .HIDDEN, |
| 3698 | .protected => .PROTECTED, | 4659 | .protected => .PROTECTED, |
| 3699 | }, | 4660 | }, |
| 3700 | }); | 4661 | .shndx = shndx, |
| 3701 | export_si.get(elf).ni = exported_ni; | 4662 | }) catch |err| switch (err) { |
| 3702 | switch (elf.symPtr(export_si)) { | 4663 | error.MultipleDefinitions => { |
| 3703 | inline else => |export_sym| { | 4664 | // HACK: because we currently don't/can't delete these exports, we would typically |
| 3704 | export_sym.size = @intCast(size); | 4665 | // get these errors on every non-initial incremental update. Hack around that by |
| 3705 | export_sym.shndx = shndx; | 4666 | // only emitting this error if the symbol we're conflicting with comes from an input |
| | 4667 | // section (as opposed to the ZCU). |
| | 4668 | const conflicting_global = elf.globalByName(try elf.string(.strtab, name)).?; |
| | 4669 | const conflicting_node = conflicting_global.symtab_index.ptr(elf).node; |
| | 4670 | if (elf.getNode(conflicting_node) == .input_section) { |
| | 4671 | return elf.base.comp.link_diags.fail( |
| | 4672 | "multiple definitions of '{s}'", |
| | 4673 | .{name}, |
| | 4674 | ); |
| | 4675 | } |
| 3706 | }, | 4676 | }, |
| 3707 | } | 4677 | }; |
| 3708 | export_si.flushMoved(elf, value); | | |
| 3709 | } | 4678 | } |
| 3710 | } | 4679 | } |
| 3711 | | 4680 | |
| ... | @@ -3759,13 +4728,13 @@ pub fn printNode( | ... | @@ -3759,13 +4728,13 @@ pub fn printNode( |
| 3759 | try w.writeByte(')'); | 4728 | try w.writeByte(')'); |
| 3760 | }, | 4729 | }, |
| 3761 | }, | 4730 | }, |
| 3762 | .section => |si| try w.print("({s})", .{elf.sectionName(si)}), | 4731 | .section => |shndx| try w.print("({s})", .{shndx.name(elf)}), |
| 3763 | .input_section => |isi| { | 4732 | .input_section => |isi| { |
| 3764 | const ii = isi.input(elf); | 4733 | const ii = isi.input(elf); |
| 3765 | try w.print("({f}{f}, {s})", .{ | 4734 | try w.print("({f}{f}, {s})", .{ |
| 3766 | ii.path(elf).fmtEscapeString(), | 4735 | ii.path(elf).fmtEscapeString(), |
| 3767 | fmtMemberString(ii.member(elf)), | 4736 | fmtMemberString(ii.member(elf)), |
| 3768 | elf.sectionName(elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section), | 4737 | elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf), |
| 3769 | }); | 4738 | }); |
| 3770 | }, | 4739 | }, |
| 3771 | .nav => |nmi| { | 4740 | .nav => |nmi| { |