| ... | ... | @@ -9,8 +9,13 @@ si: Symbol.Known, |
| 9 | 9 | symtab: std.ArrayList(Symbol), |
| 10 | 10 | shstrtab: StringTable, |
| 11 | 11 | strtab: StringTable, |
| 12 | | dynsym: std.ArrayList(Symbol.Index), |
| 12 | dynsym: std.AutoArrayHashMapUnmanaged(Symbol.Index, void), |
| 13 | 13 | dynstr: StringTable, |
| 14 | got: struct { |
| 15 | len: u32, |
| 16 | tlsld: GotIndex, |
| 17 | plt: std.AutoArrayHashMapUnmanaged(Symbol.Index, void), |
| 18 | }, |
| 14 | 19 | needed: std.AutoArrayHashMapUnmanaged(u32, void), |
| 15 | 20 | inputs: std.ArrayList(struct { |
| 16 | 21 | path: std.Build.Cache.Path, |
| ... | ... | @@ -35,8 +40,6 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct { |
| 35 | 40 | src_loc: Zcu.LazySrcLoc, |
| 36 | 41 | }), |
| 37 | 42 | relocs: std.ArrayList(Reloc), |
| 38 | | /// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly. |
| 39 | | entry_hack: Symbol.Index, |
| 40 | 43 | const_prog_node: std.Progress.Node, |
| 41 | 44 | synth_prog_node: std.Progress.Node, |
| 42 | 45 | input_prog_node: std.Progress.Node, |
| ... | ... | @@ -156,6 +159,7 @@ pub const Node = union(enum) { |
| 156 | 159 | comptime phdr: MappedFile.Node.Index = @enumFromInt(4), |
| 157 | 160 | comptime text: MappedFile.Node.Index = @enumFromInt(5), |
| 158 | 161 | comptime data: MappedFile.Node.Index = @enumFromInt(6), |
| 162 | comptime data_rel_ro: MappedFile.Node.Index = @enumFromInt(7), |
| 159 | 163 | tls: MappedFile.Node.Index, |
| 160 | 164 | }; |
| 161 | 165 | |
| ... | ... | @@ -179,71 +183,12 @@ pub const Section = struct { |
| 179 | 183 | pub fn unwrap(ri: RelIndex) ?u32 { |
| 180 | 184 | return switch (ri) { |
| 181 | 185 | .none => null, |
| 182 | | else => @intFromEnum(ri) - 1, |
| 186 | _ => @intFromEnum(ri) - 1, |
| 183 | 187 | }; |
| 184 | 188 | } |
| 185 | 189 | }; |
| 186 | 190 | }; |
| 187 | 191 | |
| 188 | | pub const StringTable = struct { |
| 189 | | map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage), |
| 190 | | |
| 191 | | const Context = struct { |
| 192 | | slice: []const u8, |
| 193 | | |
| 194 | | pub fn eql(_: Context, lhs_key: u32, rhs_key: u32) bool { |
| 195 | | return lhs_key == rhs_key; |
| 196 | | } |
| 197 | | |
| 198 | | pub fn hash(ctx: Context, key: u32) u64 { |
| 199 | | return std.hash_map.hashString(std.mem.sliceTo(ctx.slice[key..], 0)); |
| 200 | | } |
| 201 | | }; |
| 202 | | |
| 203 | | const Adapter = struct { |
| 204 | | slice: []const u8, |
| 205 | | |
| 206 | | pub fn eql(adapter: Adapter, lhs_key: []const u8, rhs_key: u32) bool { |
| 207 | | return std.mem.startsWith(u8, adapter.slice[rhs_key..], lhs_key) and |
| 208 | | adapter.slice[rhs_key + lhs_key.len] == 0; |
| 209 | | } |
| 210 | | |
| 211 | | pub fn hash(_: Adapter, key: []const u8) u64 { |
| 212 | | assert(std.mem.indexOfScalar(u8, key, 0) == null); |
| 213 | | return std.hash_map.hashString(key); |
| 214 | | } |
| 215 | | }; |
| 216 | | |
| 217 | | pub fn get(st: *StringTable, elf: *Elf, si: Symbol.Index, key: []const u8) !u32 { |
| 218 | | const gpa = elf.base.comp.gpa; |
| 219 | | const ni = si.node(elf); |
| 220 | | const slice_const = ni.sliceConst(&elf.mf); |
| 221 | | const gop = try st.map.getOrPutContextAdapted( |
| 222 | | gpa, |
| 223 | | key, |
| 224 | | StringTable.Adapter{ .slice = slice_const }, |
| 225 | | .{ .slice = slice_const }, |
| 226 | | ); |
| 227 | | if (gop.found_existing) return gop.key_ptr.*; |
| 228 | | const old_size, const new_size = size: switch (elf.shdrPtr(si.shndx(elf))) { |
| 229 | | inline else => |shdr| { |
| 230 | | const old_size: u32 = @intCast(elf.targetLoad(&shdr.size)); |
| 231 | | const new_size: u32 = @intCast(old_size + key.len + 1); |
| 232 | | elf.targetStore(&shdr.size, new_size); |
| 233 | | break :size .{ old_size, new_size }; |
| 234 | | }, |
| 235 | | }; |
| 236 | | _, const node_size = ni.location(&elf.mf).resolve(&elf.mf); |
| 237 | | if (new_size > node_size) |
| 238 | | try ni.resize(&elf.mf, gpa, new_size +| new_size / MappedFile.growth_factor); |
| 239 | | const slice = ni.slice(&elf.mf)[old_size..]; |
| 240 | | @memcpy(slice[0..key.len], key); |
| 241 | | slice[key.len] = 0; |
| 242 | | gop.key_ptr.* = old_size; |
| 243 | | return old_size; |
| 244 | | } |
| 245 | | }; |
| 246 | | |
| 247 | 192 | pub const Symbol = struct { |
| 248 | 193 | ni: MappedFile.Node.Index, |
| 249 | 194 | /// Relocations contained within this symbol |
| ... | ... | @@ -260,6 +205,11 @@ pub const Symbol = struct { |
| 260 | 205 | rodata, |
| 261 | 206 | text, |
| 262 | 207 | data, |
| 208 | data_rel_ro, |
| 209 | got, |
| 210 | got_plt, |
| 211 | plt, |
| 212 | plt_sec, |
| 263 | 213 | _, |
| 264 | 214 | |
| 265 | 215 | pub fn get(si: Symbol.Index, elf: *Elf) *Symbol { |
| ... | ... | @@ -333,7 +283,8 @@ pub const Symbol = struct { |
| 333 | 283 | shndx: Shndx = .UNDEF, |
| 334 | 284 | }; |
| 335 | 285 | pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void { |
| 336 | | const gpa = elf.base.comp.gpa; |
| 286 | const comp = elf.base.comp; |
| 287 | const gpa = comp.gpa; |
| 337 | 288 | const target_endian = elf.targetEndian(); |
| 338 | 289 | const name_strtab_entry = try elf.string(.strtab, opts.name); |
| 339 | 290 | switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) { |
| ... | ... | @@ -373,15 +324,34 @@ pub const Symbol = struct { |
| 373 | 324 | @intFromEnum(si) + 1, |
| 374 | 325 | )), |
| 375 | 326 | } |
| 376 | | if (opts.bind == .LOCAL or elf.si.dynsym == .null) return; |
| 377 | | const dsi = elf.dynsym.items.len; |
| 378 | | try elf.dynsym.append(gpa, si); |
| 327 | |
| 328 | if (opts.bind == .LOCAL) return; |
| 329 | no_entry: { |
| 330 | if (std.mem.eql(u8, opts.name, entry: switch (elf.options.entry) { |
| 331 | .default => switch (comp.config.output_mode) { |
| 332 | .Exe => continue :entry .enabled, |
| 333 | .Lib, .Obj => continue :entry .disabled, |
| 334 | }, |
| 335 | .disabled => break :no_entry, |
| 336 | .enabled => "_start", |
| 337 | .named => |named| named, |
| 338 | })) { |
| 339 | elf.si.entry = si; |
| 340 | switch (elf.ehdrPtr()) { |
| 341 | inline else => |ehdr| elf.targetStore(&ehdr.entry, @intCast(opts.value)), |
| 342 | } |
| 343 | } |
| 344 | } |
| 345 | |
| 346 | if (elf.si.dynsym == .null) return; |
| 347 | const dsi = elf.dynsym.count(); |
| 348 | try elf.dynsym.putNoClobber(gpa, si, {}); |
| 379 | 349 | const name_dynstr_entry = try elf.string(.dynstr, opts.name); |
| 380 | 350 | switch (elf.shdrPtr(elf.si.dynsym.shndx(elf))) { |
| 381 | 351 | inline else => |shdr| { |
| 382 | 352 | const old_size = elf.targetLoad(&shdr.size); |
| 383 | 353 | const ent_size = elf.targetLoad(&shdr.entsize); |
| 384 | | const new_size = ent_size * elf.dynsym.items.len; |
| 354 | const new_size = ent_size * elf.dynsym.count(); |
| 385 | 355 | if (new_size > old_size) { |
| 386 | 356 | elf.targetStore(&shdr.size, @intCast(new_size)); |
| 387 | 357 | const dynsym_ni = elf.si.dynsym.node(elf); |
| ... | ... | @@ -409,13 +379,136 @@ pub const Symbol = struct { |
| 409 | 379 | if (target_endian != native_endian) std.mem.byteSwapAllFields(Sym, dynsym); |
| 410 | 380 | }, |
| 411 | 381 | } |
| 382 | |
| 383 | if (opts.type != .FUNC or opts.shndx != .UNDEF) return; |
| 384 | const plt_index: u32 = @intCast(elf.got.plt.count()); |
| 385 | try elf.got.plt.putNoClobber(gpa, si, {}); |
| 386 | switch (elf.ehdrField(.machine)) { |
| 387 | else => |machine| @panic(@tagName(machine)), |
| 388 | .X86_64 => { |
| 389 | const plt_ni = elf.si.plt.node(elf); |
| 390 | _, const plt_node_size = plt_ni.location(&elf.mf).resolve(&elf.mf); |
| 391 | const plt_addr = plt_addr: switch (elf.shdrPtr(elf.si.plt.shndx(elf))) { |
| 392 | inline else => |shdr| { |
| 393 | const old_size = 16 * (1 + plt_index); |
| 394 | const new_size = old_size + 16; |
| 395 | elf.targetStore(&shdr.size, new_size); |
| 396 | if (new_size > plt_node_size) try plt_ni.resize( |
| 397 | &elf.mf, |
| 398 | gpa, |
| 399 | new_size +| new_size / MappedFile.growth_factor, |
| 400 | ); |
| 401 | const plt_slice = plt_ni.slice(&elf.mf)[old_size..new_size]; |
| 402 | @memcpy(plt_slice, &[16]u8{ |
| 403 | 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 |
| 404 | 0x68, 0x00, 0x00, 0x00, 0x00, // push $0x0 |
| 405 | 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp 0 |
| 406 | 0x66, 0x90, // xchg %ax,%ax |
| 407 | }); |
| 408 | std.mem.writeInt(u32, plt_slice[5..][0..4], plt_index, target_endian); |
| 409 | std.mem.writeInt( |
| 410 | i32, |
| 411 | plt_slice[10..][0..4], |
| 412 | 2 - @as(i32, @intCast(new_size)), |
| 413 | target_endian, |
| 414 | ); |
| 415 | break :plt_addr elf.targetLoad(&shdr.addr) + old_size; |
| 416 | }, |
| 417 | }; |
| 418 | |
| 419 | const got_plt_shndx = elf.si.got_plt.shndx(elf); |
| 420 | const got_plt_ni = elf.si.got_plt.node(elf); |
| 421 | _, const got_plt_node_size = got_plt_ni.location(&elf.mf).resolve(&elf.mf); |
| 422 | const got_plt_addr = got_plt_addr: switch (elf.shdrPtr(got_plt_shndx)) { |
| 423 | inline else => |shdr, class| { |
| 424 | const Addr = class.ElfN().Addr; |
| 425 | const addr_size = @sizeOf(Addr); |
| 426 | const old_size = addr_size * (3 + plt_index); |
| 427 | const new_size = old_size + addr_size; |
| 428 | elf.targetStore(&shdr.size, new_size); |
| 429 | if (new_size > got_plt_node_size) try got_plt_ni.resize( |
| 430 | &elf.mf, |
| 431 | gpa, |
| 432 | new_size +| new_size / MappedFile.growth_factor, |
| 433 | ); |
| 434 | std.mem.writeInt( |
| 435 | Addr, |
| 436 | got_plt_ni.slice(&elf.mf)[old_size..][0..addr_size], |
| 437 | @intCast(plt_addr), |
| 438 | target_endian, |
| 439 | ); |
| 440 | break :got_plt_addr elf.targetLoad(&shdr.addr) + old_size; |
| 441 | }, |
| 442 | }; |
| 443 | |
| 444 | const plt_sec_ni = elf.si.plt_sec.node(elf); |
| 445 | _, const plt_sec_node_size = plt_sec_ni.location(&elf.mf).resolve(&elf.mf); |
| 446 | switch (elf.shdrPtr(elf.si.plt_sec.shndx(elf))) { |
| 447 | inline else => |shdr| { |
| 448 | const old_size = 16 * plt_index; |
| 449 | const new_size = old_size + 16; |
| 450 | elf.targetStore(&shdr.size, new_size); |
| 451 | if (new_size > plt_sec_node_size) try plt_sec_ni.resize( |
| 452 | &elf.mf, |
| 453 | gpa, |
| 454 | new_size +| new_size / MappedFile.growth_factor, |
| 455 | ); |
| 456 | const plt_sec_slice = plt_sec_ni.slice(&elf.mf)[old_size..new_size]; |
| 457 | @memcpy(plt_sec_slice, &[16]u8{ |
| 458 | 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 |
| 459 | 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0(%rip) |
| 460 | 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00, // nopw 0x0(%rax,%rax,1) |
| 461 | }); |
| 462 | std.mem.writeInt( |
| 463 | i32, |
| 464 | plt_sec_slice[6..][0..4], |
| 465 | @intCast(@as(i64, @bitCast( |
| 466 | got_plt_addr -% (elf.targetLoad(&shdr.addr) + old_size + 10), |
| 467 | ))), |
| 468 | target_endian, |
| 469 | ); |
| 470 | }, |
| 471 | } |
| 472 | |
| 473 | const rela_plt_si = got_plt_shndx.get(elf).rela_si; |
| 474 | const rela_plt_ni = rela_plt_si.node(elf); |
| 475 | _, const rela_plt_node_size = rela_plt_ni.location(&elf.mf).resolve(&elf.mf); |
| 476 | switch (elf.shdrPtr(rela_plt_si.shndx(elf))) { |
| 477 | inline else => |shdr, class| { |
| 478 | const Rela = class.ElfN().Rela; |
| 479 | const rela_size = elf.targetLoad(&shdr.entsize); |
| 480 | const old_size = rela_size * plt_index; |
| 481 | const new_size = old_size + rela_size; |
| 482 | elf.targetStore(&shdr.size, new_size); |
| 483 | if (new_size > rela_plt_node_size) try rela_plt_ni.resize( |
| 484 | &elf.mf, |
| 485 | gpa, |
| 486 | new_size +| new_size / MappedFile.growth_factor, |
| 487 | ); |
| 488 | const rela: *Rela = @ptrCast(@alignCast( |
| 489 | rela_plt_ni.slice(&elf.mf)[@intCast(old_size)..@intCast(new_size)], |
| 490 | )); |
| 491 | rela.* = .{ |
| 492 | .offset = @intCast(got_plt_addr), |
| 493 | .info = .{ |
| 494 | .type = @intFromEnum(std.elf.R_X86_64.JUMP_SLOT), |
| 495 | .sym = @intCast(dsi), |
| 496 | }, |
| 497 | .addend = 0, |
| 498 | }; |
| 499 | if (target_endian != native_endian) std.mem.byteSwapAllFields(Rela, rela); |
| 500 | }, |
| 501 | } |
| 502 | try rela_plt_ni.resized(gpa, &elf.mf); |
| 503 | }, |
| 504 | } |
| 412 | 505 | } |
| 413 | 506 | |
| 414 | 507 | pub fn flushMoved(si: Symbol.Index, elf: *Elf, value: u64) void { |
| 415 | 508 | switch (elf.symPtr(si)) { |
| 416 | 509 | inline else => |sym, class| { |
| 417 | 510 | elf.targetStore(&sym.value, @intCast(value)); |
| 418 | | if (si == elf.entry_hack) { |
| 511 | if (si == elf.si.entry) { |
| 419 | 512 | @branchHint(.unlikely); |
| 420 | 513 | @field(elf.ehdrPtr(), @tagName(class)).entry = sym.value; |
| 421 | 514 | } |
| ... | ... | @@ -464,10 +557,16 @@ pub const Symbol = struct { |
| 464 | 557 | comptime rodata: Symbol.Index = .rodata, |
| 465 | 558 | comptime text: Symbol.Index = .text, |
| 466 | 559 | comptime data: Symbol.Index = .data, |
| 560 | comptime data_rel_ro: Symbol.Index = .data_rel_ro, |
| 561 | comptime got: Symbol.Index = .got, |
| 562 | comptime got_plt: Symbol.Index = .got_plt, |
| 563 | comptime plt: Symbol.Index = .plt, |
| 564 | comptime plt_sec: Symbol.Index = .plt_sec, |
| 467 | 565 | dynsym: Symbol.Index, |
| 468 | 566 | dynstr: Symbol.Index, |
| 469 | 567 | dynamic: Symbol.Index, |
| 470 | 568 | tdata: Symbol.Index, |
| 569 | entry: Symbol.Index, |
| 471 | 570 | }; |
| 472 | 571 | |
| 473 | 572 | comptime { |
| ... | ... | @@ -475,6 +574,83 @@ pub const Symbol = struct { |
| 475 | 574 | } |
| 476 | 575 | }; |
| 477 | 576 | |
| 577 | pub const StringTable = struct { |
| 578 | map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage), |
| 579 | |
| 580 | const Context = struct { |
| 581 | slice: []const u8, |
| 582 | |
| 583 | pub fn eql(_: Context, lhs_key: u32, rhs_key: u32) bool { |
| 584 | return lhs_key == rhs_key; |
| 585 | } |
| 586 | |
| 587 | pub fn hash(ctx: Context, key: u32) u64 { |
| 588 | return std.hash_map.hashString(std.mem.sliceTo(ctx.slice[key..], 0)); |
| 589 | } |
| 590 | }; |
| 591 | |
| 592 | const Adapter = struct { |
| 593 | slice: []const u8, |
| 594 | |
| 595 | pub fn eql(adapter: Adapter, lhs_key: []const u8, rhs_key: u32) bool { |
| 596 | return std.mem.startsWith(u8, adapter.slice[rhs_key..], lhs_key) and |
| 597 | adapter.slice[rhs_key + lhs_key.len] == 0; |
| 598 | } |
| 599 | |
| 600 | pub fn hash(_: Adapter, key: []const u8) u64 { |
| 601 | assert(std.mem.indexOfScalar(u8, key, 0) == null); |
| 602 | return std.hash_map.hashString(key); |
| 603 | } |
| 604 | }; |
| 605 | |
| 606 | pub fn get(st: *StringTable, elf: *Elf, si: Symbol.Index, key: []const u8) !u32 { |
| 607 | const gpa = elf.base.comp.gpa; |
| 608 | const ni = si.node(elf); |
| 609 | const slice_const = ni.sliceConst(&elf.mf); |
| 610 | const gop = try st.map.getOrPutContextAdapted( |
| 611 | gpa, |
| 612 | key, |
| 613 | StringTable.Adapter{ .slice = slice_const }, |
| 614 | .{ .slice = slice_const }, |
| 615 | ); |
| 616 | if (gop.found_existing) return gop.key_ptr.*; |
| 617 | try ni.resized(gpa, &elf.mf); |
| 618 | const old_size, const new_size = size: switch (elf.shdrPtr(si.shndx(elf))) { |
| 619 | inline else => |shdr| { |
| 620 | const old_size: u32 = @intCast(elf.targetLoad(&shdr.size)); |
| 621 | const new_size: u32 = @intCast(old_size + key.len + 1); |
| 622 | elf.targetStore(&shdr.size, new_size); |
| 623 | break :size .{ old_size, new_size }; |
| 624 | }, |
| 625 | }; |
| 626 | _, const node_size = ni.location(&elf.mf).resolve(&elf.mf); |
| 627 | if (new_size > node_size) |
| 628 | try ni.resize(&elf.mf, gpa, new_size +| new_size / MappedFile.growth_factor); |
| 629 | const slice = ni.slice(&elf.mf)[old_size..]; |
| 630 | @memcpy(slice[0..key.len], key); |
| 631 | slice[key.len] = 0; |
| 632 | gop.key_ptr.* = old_size; |
| 633 | return old_size; |
| 634 | } |
| 635 | }; |
| 636 | |
| 637 | pub const GotIndex = enum(u32) { |
| 638 | none = std.math.maxInt(u32), |
| 639 | _, |
| 640 | |
| 641 | pub fn wrap(i: ?u32) GotIndex { |
| 642 | const gi: GotIndex = @enumFromInt(i orelse return .none); |
| 643 | assert(gi != .none); |
| 644 | return gi; |
| 645 | } |
| 646 | pub fn unwrap(gi: GotIndex) ?u32 { |
| 647 | return switch (gi) { |
| 648 | _ => @intFromEnum(gi), |
| 649 | .none => null, |
| 650 | }; |
| 651 | } |
| 652 | }; |
| 653 | |
| 478 | 654 | pub const Reloc = extern struct { |
| 479 | 655 | type: Reloc.Type, |
| 480 | 656 | prev: Reloc.Index, |
| ... | ... | @@ -500,7 +676,6 @@ pub const Reloc = extern struct { |
| 500 | 676 | .X86_64 => .{ .X86_64 = .NONE }, |
| 501 | 677 | }; |
| 502 | 678 | } |
| 503 | | |
| 504 | 679 | pub fn absAddr(elf: *Elf) Reloc.Type { |
| 505 | 680 | return switch (elf.ehdrField(.machine)) { |
| 506 | 681 | else => unreachable, |
| ... | ... | @@ -510,7 +685,6 @@ pub const Reloc = extern struct { |
| 510 | 685 | .X86_64 => .{ .X86_64 = .@"64" }, |
| 511 | 686 | }; |
| 512 | 687 | } |
| 513 | | |
| 514 | 688 | pub fn sizeAddr(elf: *Elf) Reloc.Type { |
| 515 | 689 | return switch (elf.ehdrField(.machine)) { |
| 516 | 690 | else => unreachable, |
| ... | ... | @@ -528,7 +702,6 @@ pub const Reloc = extern struct { |
| 528 | 702 | => |machine| @unionInit(Reloc.Type, @tagName(machine), @enumFromInt(int)), |
| 529 | 703 | }; |
| 530 | 704 | } |
| 531 | | |
| 532 | 705 | pub fn unwrap(rt: Reloc.Type, elf: *Elf) u32 { |
| 533 | 706 | return switch (elf.ehdrField(.machine)) { |
| 534 | 707 | else => unreachable, |
| ... | ... | @@ -558,7 +731,7 @@ pub const Reloc = extern struct { |
| 558 | 731 | else => |ni| if (ni.hasMoved(&elf.mf)) return, |
| 559 | 732 | } |
| 560 | 733 | switch (reloc.target.get(elf).ni) { |
| 561 | | .none => return, |
| 734 | .none => {}, |
| 562 | 735 | else => |ni| if (ni.hasMoved(&elf.mf)) return, |
| 563 | 736 | } |
| 564 | 737 | const loc_slice = loc_ni.slice(&elf.mf)[@intCast(reloc.offset)..]; |
| ... | ... | @@ -568,7 +741,6 @@ pub const Reloc = extern struct { |
| 568 | 741 | const loc_sym = &symtab[@intFromEnum(reloc.loc)]; |
| 569 | 742 | const loc_shndx = elf.targetLoad(&loc_sym.shndx); |
| 570 | 743 | assert(loc_shndx != std.elf.SHN_UNDEF); |
| 571 | | const loc_value = elf.targetLoad(&loc_sym.value) + reloc.offset; |
| 572 | 744 | const target_sym = &symtab[@intFromEnum(reloc.target)]; |
| 573 | 745 | const target_value = |
| 574 | 746 | elf.targetLoad(&target_sym.value) +% @as(u64, @bitCast(reloc.addend)); |
| ... | ... | @@ -582,10 +754,28 @@ pub const Reloc = extern struct { |
| 582 | 754 | target_value, |
| 583 | 755 | target_endian, |
| 584 | 756 | ), |
| 585 | | .PC32, .PLT32 => std.mem.writeInt( |
| 757 | .PC32 => std.mem.writeInt( |
| 758 | i32, |
| 759 | loc_slice[0..4], |
| 760 | @intCast(@as(i64, @bitCast(target_value -% |
| 761 | (elf.targetLoad(&loc_sym.value) + reloc.offset)))), |
| 762 | target_endian, |
| 763 | ), |
| 764 | .PLT32 => std.mem.writeInt( |
| 586 | 765 | i32, |
| 587 | 766 | loc_slice[0..4], |
| 588 | | @intCast(@as(i64, @bitCast(target_value -% loc_value))), |
| 767 | @intCast(@as(i64, @bitCast( |
| 768 | if (elf.got.plt.getIndex(reloc.target)) |plt_index| |
| 769 | elf.targetLoad(&@field( |
| 770 | elf.shdrPtr(elf.si.plt_sec.shndx(elf)), |
| 771 | @tagName(class), |
| 772 | ).addr) +% 16 * plt_index +% |
| 773 | @as(u64, @bitCast(reloc.addend)) -% |
| 774 | (elf.targetLoad(&loc_sym.value) + reloc.offset) |
| 775 | else |
| 776 | target_value -% |
| 777 | (elf.targetLoad(&loc_sym.value) + reloc.offset), |
| 778 | ))), |
| 589 | 779 | target_endian, |
| 590 | 780 | ), |
| 591 | 781 | .@"32" => std.mem.writeInt( |
| ... | ... | @@ -600,6 +790,23 @@ pub const Reloc = extern struct { |
| 600 | 790 | @intCast(@as(i64, @bitCast(target_value))), |
| 601 | 791 | target_endian, |
| 602 | 792 | ), |
| 793 | .TLSLD => std.mem.writeInt( |
| 794 | i32, |
| 795 | loc_slice[0..4], |
| 796 | @intCast(@as(i64, @bitCast( |
| 797 | elf.targetLoad(&symtab[@intFromEnum(elf.si.got)].value) +% |
| 798 | @as(u64, @bitCast(reloc.addend)) +% |
| 799 | @as(u64, 8) * elf.got.tlsld.unwrap().? -% |
| 800 | (elf.targetLoad(&loc_sym.value) + reloc.offset), |
| 801 | ))), |
| 802 | target_endian, |
| 803 | ), |
| 804 | .DTPOFF32 => std.mem.writeInt( |
| 805 | i32, |
| 806 | loc_slice[0..4], |
| 807 | @intCast(@as(i64, @bitCast(target_value))), |
| 808 | target_endian, |
| 809 | ), |
| 603 | 810 | .TPOFF32 => { |
| 604 | 811 | const phdr = @field(elf.phdrSlice(), @tagName(class)); |
| 605 | 812 | const ph = &phdr[elf.getNode(elf.ni.tls).segment]; |
| ... | ... | @@ -614,13 +821,15 @@ pub const Reloc = extern struct { |
| 614 | 821 | .SIZE32 => std.mem.writeInt( |
| 615 | 822 | u32, |
| 616 | 823 | loc_slice[0..4], |
| 617 | | @intCast(elf.targetLoad(&target_sym.size)), |
| 824 | @intCast( |
| 825 | elf.targetLoad(&target_sym.size) +% @as(u64, @bitCast(reloc.addend)), |
| 826 | ), |
| 618 | 827 | target_endian, |
| 619 | 828 | ), |
| 620 | 829 | .SIZE64 => std.mem.writeInt( |
| 621 | 830 | u64, |
| 622 | 831 | loc_slice[0..8], |
| 623 | | @intCast(elf.targetLoad(&target_sym.size)), |
| 832 | elf.targetLoad(&target_sym.size) +% @as(u64, @bitCast(reloc.addend)), |
| 624 | 833 | target_endian, |
| 625 | 834 | ), |
| 626 | 835 | }, |
| ... | ... | @@ -711,7 +920,7 @@ fn create( |
| 711 | 920 | .big => .@"2MSB", |
| 712 | 921 | }; |
| 713 | 922 | const osabi: std.elf.OSABI = switch (target.os.tag) { |
| 714 | | else => .NONE, |
| 923 | else => if (target.abi.isGnu()) .GNU else .NONE, |
| 715 | 924 | .freestanding, .other => .STANDALONE, |
| 716 | 925 | .netbsd => .NETBSD, |
| 717 | 926 | .illumos => .SOLARIS, |
| ... | ... | @@ -776,6 +985,7 @@ fn create( |
| 776 | 985 | .dynstr = .null, |
| 777 | 986 | .dynamic = .null, |
| 778 | 987 | .tdata = .null, |
| 988 | .entry = .null, |
| 779 | 989 | }, |
| 780 | 990 | .symtab = .empty, |
| 781 | 991 | .shstrtab = .{ |
| ... | ... | @@ -788,6 +998,11 @@ fn create( |
| 788 | 998 | .dynstr = .{ |
| 789 | 999 | .map = .empty, |
| 790 | 1000 | }, |
| 1001 | .got = .{ |
| 1002 | .len = 0, |
| 1003 | .tlsld = .none, |
| 1004 | .plt = .empty, |
| 1005 | }, |
| 791 | 1006 | .needed = .empty, |
| 792 | 1007 | .inputs = .empty, |
| 793 | 1008 | .input_sections = .empty, |
| ... | ... | @@ -801,7 +1016,6 @@ fn create( |
| 801 | 1016 | }), |
| 802 | 1017 | .pending_uavs = .empty, |
| 803 | 1018 | .relocs = .empty, |
| 804 | | .entry_hack = .null, |
| 805 | 1019 | .const_prog_node = .none, |
| 806 | 1020 | .synth_prog_node = .none, |
| 807 | 1021 | .input_prog_node = .none, |
| ... | ... | @@ -823,6 +1037,7 @@ pub fn deinit(elf: *Elf) void { |
| 823 | 1037 | elf.strtab.map.deinit(gpa); |
| 824 | 1038 | elf.dynsym.deinit(gpa); |
| 825 | 1039 | elf.dynstr.map.deinit(gpa); |
| 1040 | elf.got.plt.deinit(gpa); |
| 826 | 1041 | elf.needed.deinit(gpa); |
| 827 | 1042 | for (elf.inputs.items) |input| if (input.member) |m| gpa.free(m); |
| 828 | 1043 | elf.inputs.deinit(gpa); |
| ... | ... | @@ -873,14 +1088,16 @@ fn initHeaders( |
| 873 | 1088 | phnum += 1; |
| 874 | 1089 | const data_phndx = phnum; |
| 875 | 1090 | phnum += 1; |
| 876 | | const dynamic_phndx = if (have_dynamic_section) phndx: { |
| 1091 | const tls_phndx = if (comp.config.any_non_single_threaded) phndx: { |
| 877 | 1092 | defer phnum += 1; |
| 878 | 1093 | break :phndx phnum; |
| 879 | 1094 | } else undefined; |
| 880 | | const tls_phndx = if (comp.config.any_non_single_threaded) phndx: { |
| 1095 | const dynamic_phndx = if (have_dynamic_section) phndx: { |
| 881 | 1096 | defer phnum += 1; |
| 882 | 1097 | break :phndx phnum; |
| 883 | 1098 | } else undefined; |
| 1099 | const relro_phndx = phnum; |
| 1100 | phnum += 1; |
| 884 | 1101 | |
| 885 | 1102 | const expected_nodes_len = expected_nodes_len: switch (@"type") { |
| 886 | 1103 | .NONE, .CORE, _ => unreachable, |
| ... | ... | @@ -888,12 +1105,14 @@ fn initHeaders( |
| 888 | 1105 | defer phnum = 0; |
| 889 | 1106 | break :expected_nodes_len 5 + phnum; |
| 890 | 1107 | }, |
| 891 | | .EXEC, .DYN => break :expected_nodes_len 5 + phnum * 2 + |
| 892 | | @as(usize, 2) * @intFromBool(have_dynamic_section), |
| 1108 | .EXEC, .DYN => break :expected_nodes_len 9 + phnum * 2 + |
| 1109 | @as(usize, 4) * @intFromBool(have_dynamic_section), |
| 893 | 1110 | }; |
| 894 | 1111 | try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len); |
| 895 | 1112 | try elf.shdrs.ensureTotalCapacity(gpa, shnum); |
| 896 | 1113 | try elf.phdrs.resize(gpa, phnum); |
| 1114 | try elf.symtab.ensureTotalCapacity(gpa, 1); |
| 1115 | if (have_dynamic_section) try elf.dynsym.ensureTotalCapacity(gpa, 1); |
| 897 | 1116 | elf.nodes.appendAssumeCapacity(.file); |
| 898 | 1117 | |
| 899 | 1118 | switch (class) { |
| ... | ... | @@ -976,10 +1195,18 @@ fn initHeaders( |
| 976 | 1195 | elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx }); |
| 977 | 1196 | elf.phdrs.items[data_phndx] = elf.ni.data; |
| 978 | 1197 | |
| 1198 | assert(elf.ni.data_rel_ro == try elf.mf.addOnlyChildNode(gpa, elf.ni.data, .{ |
| 1199 | .alignment = elf.mf.flags.block_size, |
| 1200 | .moved = true, |
| 1201 | .bubbles_moved = false, |
| 1202 | })); |
| 1203 | elf.nodes.appendAssumeCapacity(.{ .segment = relro_phndx }); |
| 1204 | elf.phdrs.items[relro_phndx] = elf.ni.data_rel_ro; |
| 1205 | |
| 979 | 1206 | break :ph_vaddr switch (elf.ehdrField(.type)) { |
| 980 | 1207 | .NONE, .CORE, _ => unreachable, |
| 981 | 1208 | .REL, .DYN => 0, |
| 982 | | .EXEC => switch (elf.ehdrField(.machine)) { |
| 1209 | .EXEC => switch (machine) { |
| 983 | 1210 | .@"386" => 0x400000, |
| 984 | 1211 | .AARCH64, .X86_64 => 0x200000, |
| 985 | 1212 | .PPC, .PPC64 => 0x10000000, |
| ... | ... | @@ -1070,35 +1297,48 @@ fn initHeaders( |
| 1070 | 1297 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data); |
| 1071 | 1298 | ph_vaddr += @intCast(data_size); |
| 1072 | 1299 | |
| 1073 | | if (have_dynamic_section) { |
| 1074 | | const ph_dynamic = &phdr[dynamic_phndx]; |
| 1075 | | ph_dynamic.* = .{ |
| 1076 | | .type = .DYNAMIC, |
| 1300 | if (comp.config.any_non_single_threaded) { |
| 1301 | const ph_tls = &phdr[tls_phndx]; |
| 1302 | ph_tls.* = .{ |
| 1303 | .type = .TLS, |
| 1077 | 1304 | .offset = 0, |
| 1078 | 1305 | .vaddr = 0, |
| 1079 | 1306 | .paddr = 0, |
| 1080 | 1307 | .filesz = 0, |
| 1081 | 1308 | .memsz = 0, |
| 1082 | | .flags = .{ .R = true, .W = true }, |
| 1083 | | .@"align" = @intCast(addr_align.toByteUnits()), |
| 1309 | .flags = .{ .R = true }, |
| 1310 | .@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()), |
| 1084 | 1311 | }; |
| 1085 | | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_dynamic); |
| 1312 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls); |
| 1086 | 1313 | } |
| 1087 | 1314 | |
| 1088 | | if (comp.config.any_non_single_threaded) { |
| 1089 | | const ph_tls = &phdr[tls_phndx]; |
| 1090 | | ph_tls.* = .{ |
| 1091 | | .type = .TLS, |
| 1315 | if (have_dynamic_section) { |
| 1316 | const ph_dynamic = &phdr[dynamic_phndx]; |
| 1317 | ph_dynamic.* = .{ |
| 1318 | .type = .DYNAMIC, |
| 1092 | 1319 | .offset = 0, |
| 1093 | 1320 | .vaddr = 0, |
| 1094 | 1321 | .paddr = 0, |
| 1095 | 1322 | .filesz = 0, |
| 1096 | 1323 | .memsz = 0, |
| 1097 | | .flags = .{ .R = true }, |
| 1098 | | .@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()), |
| 1324 | .flags = .{ .R = true, .W = true }, |
| 1325 | .@"align" = @intCast(addr_align.toByteUnits()), |
| 1099 | 1326 | }; |
| 1100 | | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls); |
| 1327 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_dynamic); |
| 1101 | 1328 | } |
| 1329 | |
| 1330 | const ph_relro = &phdr[relro_phndx]; |
| 1331 | ph_relro.* = .{ |
| 1332 | .type = .GNU_RELRO, |
| 1333 | .offset = 0, |
| 1334 | .vaddr = 0, |
| 1335 | .paddr = 0, |
| 1336 | .filesz = 0, |
| 1337 | .memsz = 0, |
| 1338 | .flags = .{ .R = true }, |
| 1339 | .@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()), |
| 1340 | }; |
| 1341 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_relro); |
| 1102 | 1342 | } |
| 1103 | 1343 | |
| 1104 | 1344 | const sh_undef: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf))); |
| ... | ... | @@ -1117,7 +1357,6 @@ fn initHeaders( |
| 1117 | 1357 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef); |
| 1118 | 1358 | elf.shdrs.appendAssumeCapacity(.{ .si = .null, .rela_si = .null, .rela_free = .none }); |
| 1119 | 1359 | |
| 1120 | | try elf.symtab.ensureTotalCapacity(gpa, 1); |
| 1121 | 1360 | elf.symtab.addOneAssumeCapacity().* = .{ |
| 1122 | 1361 | .ni = .none, |
| 1123 | 1362 | .loc_relocs = .none, |
| ... | ... | @@ -1163,7 +1402,9 @@ fn initHeaders( |
| 1163 | 1402 | .entsize = 1, |
| 1164 | 1403 | .node_align = elf.mf.flags.block_size, |
| 1165 | 1404 | })); |
| 1166 | | try elf.linkSections(.symtab, .strtab); |
| 1405 | switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) { |
| 1406 | inline else => |shdr| elf.targetStore(&shdr.link, @intFromEnum(elf.si.strtab.shndx(elf))), |
| 1407 | } |
| 1167 | 1408 | elf.si.strtab.node(elf).slice(&elf.mf)[0] = 0; |
| 1168 | 1409 | |
| 1169 | 1410 | assert(elf.si.rodata == try elf.addSection(elf.ni.rodata, .{ |
| ... | ... | @@ -1181,7 +1422,50 @@ fn initHeaders( |
| 1181 | 1422 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 1182 | 1423 | .addralign = elf.mf.flags.block_size, |
| 1183 | 1424 | })); |
| 1425 | assert(elf.si.data_rel_ro == try elf.addSection(elf.ni.data_rel_ro, .{ |
| 1426 | .name = ".data.rel.ro", |
| 1427 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 1428 | .addralign = elf.mf.flags.block_size, |
| 1429 | })); |
| 1184 | 1430 | if (@"type" != .REL) { |
| 1431 | assert(elf.si.got == try elf.addSection(elf.ni.data_rel_ro, .{ |
| 1432 | .name = ".got", |
| 1433 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 1434 | .addralign = addr_align, |
| 1435 | })); |
| 1436 | assert(elf.si.got_plt == try elf.addSection( |
| 1437 | if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data, |
| 1438 | .{ |
| 1439 | .name = ".got.plt", |
| 1440 | .type = .PROGBITS, |
| 1441 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 1442 | .size = switch (machine) { |
| 1443 | else => @panic(@tagName(machine)), |
| 1444 | .@"386" => 3 * 4, |
| 1445 | .X86_64 => 3 * 8, |
| 1446 | }, |
| 1447 | .addralign = addr_align, |
| 1448 | }, |
| 1449 | )); |
| 1450 | const plt_size: std.elf.Xword, const plt_align: std.mem.Alignment, const plt_sec = |
| 1451 | switch (machine) { |
| 1452 | else => @panic(@tagName(machine)), |
| 1453 | .X86_64 => .{ 16, .@"16", true }, |
| 1454 | }; |
| 1455 | assert(elf.si.plt == try elf.addSection(elf.ni.text, .{ |
| 1456 | .name = ".plt", |
| 1457 | .type = .PROGBITS, |
| 1458 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, |
| 1459 | .size = plt_size, |
| 1460 | .addralign = plt_align, |
| 1461 | .node_align = elf.mf.flags.block_size, |
| 1462 | })); |
| 1463 | if (plt_sec) assert(elf.si.plt_sec == try elf.addSection(elf.ni.text, .{ |
| 1464 | .name = ".plt.sec", |
| 1465 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, |
| 1466 | .addralign = plt_align, |
| 1467 | .node_align = elf.mf.flags.block_size, |
| 1468 | })); |
| 1185 | 1469 | if (maybe_interp) |interp| { |
| 1186 | 1470 | const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{ |
| 1187 | 1471 | .size = interp.len + 1, |
| ... | ... | @@ -1193,8 +1477,8 @@ fn initHeaders( |
| 1193 | 1477 | elf.phdrs.items[interp_phndx] = interp_ni; |
| 1194 | 1478 | |
| 1195 | 1479 | const sec_interp_si = try elf.addSection(interp_ni, .{ |
| 1196 | | .type = .PROGBITS, |
| 1197 | 1480 | .name = ".interp", |
| 1481 | .type = .PROGBITS, |
| 1198 | 1482 | .flags = .{ .ALLOC = true }, |
| 1199 | 1483 | .size = @intCast(interp.len + 1), |
| 1200 | 1484 | }); |
| ... | ... | @@ -1203,13 +1487,24 @@ fn initHeaders( |
| 1203 | 1487 | sec_interp[interp.len] = 0; |
| 1204 | 1488 | } |
| 1205 | 1489 | if (have_dynamic_section) { |
| 1206 | | const dynamic_ni = try elf.mf.addLastChildNode(gpa, elf.ni.data, .{ |
| 1490 | const dynamic_ni = try elf.mf.addLastChildNode(gpa, elf.ni.data_rel_ro, .{ |
| 1491 | .alignment = addr_align, |
| 1207 | 1492 | .moved = true, |
| 1208 | 1493 | .bubbles_moved = false, |
| 1209 | 1494 | }); |
| 1210 | 1495 | elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx }); |
| 1211 | 1496 | elf.phdrs.items[dynamic_phndx] = dynamic_ni; |
| 1212 | 1497 | |
| 1498 | elf.si.dynstr = try elf.addSection(elf.ni.rodata, .{ |
| 1499 | .name = ".dynstr", |
| 1500 | .type = .STRTAB, |
| 1501 | .flags = .{ .ALLOC = true }, |
| 1502 | .size = 1, |
| 1503 | .entsize = 1, |
| 1504 | .node_align = elf.mf.flags.block_size, |
| 1505 | }); |
| 1506 | const dynstr_shndx = elf.si.dynstr.shndx(elf); |
| 1507 | elf.dynsym.putAssumeCapacityNoClobber(.null, {}); |
| 1213 | 1508 | switch (class) { |
| 1214 | 1509 | .NONE, _ => unreachable, |
| 1215 | 1510 | inline else => |ct_class| { |
| ... | ... | @@ -1217,7 +1512,10 @@ fn initHeaders( |
| 1217 | 1512 | elf.si.dynsym = try elf.addSection(elf.ni.rodata, .{ |
| 1218 | 1513 | .name = ".dynsym", |
| 1219 | 1514 | .type = .DYNSYM, |
| 1515 | .flags = .{ .ALLOC = true }, |
| 1220 | 1516 | .size = @sizeOf(Sym) * 1, |
| 1517 | .link = @intFromEnum(dynstr_shndx), |
| 1518 | .info = 1, |
| 1221 | 1519 | .addralign = addr_align, |
| 1222 | 1520 | .entsize = @sizeOf(Sym), |
| 1223 | 1521 | .node_align = elf.mf.flags.block_size, |
| ... | ... | @@ -1237,21 +1535,66 @@ fn initHeaders( |
| 1237 | 1535 | ); |
| 1238 | 1536 | }, |
| 1239 | 1537 | } |
| 1240 | | elf.si.dynstr = try elf.addSection(elf.ni.rodata, .{ |
| 1241 | | .name = ".dynstr", |
| 1242 | | .type = .STRTAB, |
| 1243 | | .size = 1, |
| 1244 | | .entsize = 1, |
| 1538 | const rela_size: std.elf.Word = switch (class) { |
| 1539 | .NONE, _ => unreachable, |
| 1540 | inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela), |
| 1541 | }; |
| 1542 | elf.si.got.shndx(elf).get(elf).rela_si = try elf.addSection(elf.ni.rodata, .{ |
| 1543 | .name = ".rela.dyn", |
| 1544 | .type = .RELA, |
| 1545 | .flags = .{ .ALLOC = true }, |
| 1546 | .link = @intFromEnum(elf.si.dynsym.shndx(elf)), |
| 1547 | .addralign = addr_align, |
| 1548 | .entsize = rela_size, |
| 1549 | .node_align = elf.mf.flags.block_size, |
| 1550 | }); |
| 1551 | const got_plt_shndx = elf.si.got_plt.shndx(elf); |
| 1552 | got_plt_shndx.get(elf).rela_si = try elf.addSection(elf.ni.rodata, .{ |
| 1553 | .name = ".rela.plt", |
| 1554 | .type = .RELA, |
| 1555 | .flags = .{ .ALLOC = true, .INFO_LINK = true }, |
| 1556 | .link = @intFromEnum(elf.si.dynsym.shndx(elf)), |
| 1557 | .info = @intFromEnum(got_plt_shndx), |
| 1558 | .addralign = addr_align, |
| 1559 | .entsize = rela_size, |
| 1245 | 1560 | .node_align = elf.mf.flags.block_size, |
| 1246 | 1561 | }); |
| 1247 | 1562 | elf.si.dynamic = try elf.addSection(dynamic_ni, .{ |
| 1248 | 1563 | .name = ".dynamic", |
| 1249 | 1564 | .type = .DYNAMIC, |
| 1250 | 1565 | .flags = .{ .ALLOC = true, .WRITE = true }, |
| 1566 | .link = @intFromEnum(dynstr_shndx), |
| 1567 | .entsize = @intCast(addr_align.toByteUnits() * 2), |
| 1251 | 1568 | .node_align = addr_align, |
| 1252 | 1569 | }); |
| 1253 | | try elf.linkSections(elf.si.dynamic, elf.si.dynstr); |
| 1254 | | try elf.linkSections(elf.si.dynsym, elf.si.dynstr); |
| 1570 | switch (machine) { |
| 1571 | else => @panic(@tagName(machine)), |
| 1572 | .X86_64 => { |
| 1573 | @memcpy(elf.si.plt.node(elf).slice(&elf.mf)[0..16], &[16]u8{ |
| 1574 | 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // push 0x0(%rip) |
| 1575 | 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0(%rip) |
| 1576 | 0x0f, 0x1f, 0x40, 0x00, // nopl 0x0(%rax) |
| 1577 | }); |
| 1578 | const plt_sym = elf.si.plt.get(elf); |
| 1579 | assert(plt_sym.loc_relocs == .none); |
| 1580 | plt_sym.loc_relocs = @enumFromInt(elf.relocs.items.len); |
| 1581 | try elf.ensureUnusedRelocCapacity(elf.si.plt, 2); |
| 1582 | elf.addRelocAssumeCapacity( |
| 1583 | elf.si.plt, |
| 1584 | 2, |
| 1585 | elf.si.got_plt, |
| 1586 | 8 * 1 - 4, |
| 1587 | .{ .X86_64 = .PC32 }, |
| 1588 | ); |
| 1589 | elf.addRelocAssumeCapacity( |
| 1590 | elf.si.plt, |
| 1591 | 8, |
| 1592 | elf.si.got_plt, |
| 1593 | 8 * 2 - 4, |
| 1594 | .{ .X86_64 = .PC32 }, |
| 1595 | ); |
| 1596 | }, |
| 1597 | } |
| 1255 | 1598 | } |
| 1256 | 1599 | if (comp.config.any_non_single_threaded) { |
| 1257 | 1600 | elf.ni.tls = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{ |
| ... | ... | @@ -1305,7 +1648,8 @@ fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node { |
| 1305 | 1648 | } |
| 1306 | 1649 | fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 1307 | 1650 | const parent_vaddr = parent_vaddr: { |
| 1308 | | const parent_si = switch (elf.getNode(ni.parent(&elf.mf))) { |
| 1651 | const parent_ni = ni.parent(&elf.mf); |
| 1652 | const parent_si = switch (elf.getNode(parent_ni)) { |
| 1309 | 1653 | .file => return 0, |
| 1310 | 1654 | .ehdr, .shdr => unreachable, |
| 1311 | 1655 | .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) { |
| ... | ... | @@ -1630,7 +1974,7 @@ pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index { |
| 1630 | 1974 | } |
| 1631 | 1975 | |
| 1632 | 1976 | pub fn loadInput(elf: *Elf, input: link.Input) (std.fs.File.Reader.SizeError || |
| 1633 | | std.Io.File.Reader.Error || MappedFile.Error || error{ EndOfStream, LinkFailure })!void { |
| 1977 | std.Io.File.Reader.Error || MappedFile.Error || error{ EndOfStream, BadMagic, LinkFailure })!void { |
| 1634 | 1978 | const io = elf.base.comp.io; |
| 1635 | 1979 | var buf: [4096]u8 = undefined; |
| 1636 | 1980 | switch (input) { |
| ... | ... | @@ -1670,8 +2014,7 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) ! |
| 1670 | 2014 | const r = &fr.interface; |
| 1671 | 2015 | |
| 1672 | 2016 | log.debug("loadArchive({f})", .{path.fmtEscapeString()}); |
| 1673 | | if (!std.mem.eql(u8, try r.take(std.elf.ARMAG.len), std.elf.ARMAG)) |
| 1674 | | return diags.failParse(path, "bad magic", .{}); |
| 2017 | if (!std.mem.eql(u8, try r.take(std.elf.ARMAG.len), std.elf.ARMAG)) return error.BadMagic; |
| 1675 | 2018 | var strtab: std.Io.Writer.Allocating = .init(gpa); |
| 1676 | 2019 | defer strtab.deinit(); |
| 1677 | 2020 | while (r.takeStruct(std.elf.ar_hdr, native_endian)) |header| { |
| ... | ... | @@ -1734,8 +2077,9 @@ fn loadObject( |
| 1734 | 2077 | |
| 1735 | 2078 | const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len); |
| 1736 | 2079 | log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) }); |
| 1737 | | const ident = try r.peek(std.elf.EI.NIDENT); |
| 1738 | | if (!std.mem.eql(u8, ident, elf.mf.contents[0..std.elf.EI.NIDENT])) |
| 2080 | const ident = try r.peek(std.elf.EI.OSABI); |
| 2081 | if (!std.mem.eql(u8, ident[0..std.elf.MAGIC.len], std.elf.MAGIC)) return error.BadMagic; |
| 2082 | if (!std.mem.eql(u8, ident[std.elf.MAGIC.len..], elf.mf.contents[std.elf.MAGIC.len..ident.len])) |
| 1739 | 2083 | return diags.failParse(path, "bad ident", .{}); |
| 1740 | 2084 | try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| 1741 | 2085 | try elf.inputs.ensureUnusedCapacity(gpa, 1); |
| ... | ... | @@ -1973,7 +2317,8 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void |
| 1973 | 2317 | |
| 1974 | 2318 | log.debug("loadDso({f})", .{path.fmtEscapeString()}); |
| 1975 | 2319 | const ident = try r.peek(std.elf.EI.NIDENT); |
| 1976 | | if (!std.mem.eql(u8, ident, elf.mf.contents[0..std.elf.EI.NIDENT])) |
| 2320 | if (!std.mem.eql(u8, ident[0..std.elf.MAGIC.len], std.elf.MAGIC)) return error.BadMagic; |
| 2321 | if (!std.mem.eql(u8, ident[std.elf.MAGIC.len..], elf.mf.contents[std.elf.MAGIC.len..ident.len])) |
| 1977 | 2322 | return diags.failParse(path, "bad ident", .{}); |
| 1978 | 2323 | const target_endian = elf.targetEndian(); |
| 1979 | 2324 | switch (elf.identClass()) { |
| ... | ... | @@ -2053,7 +2398,8 @@ pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void { |
| 2053 | 2398 | }; |
| 2054 | 2399 | } |
| 2055 | 2400 | fn prelinkInner(elf: *Elf) !void { |
| 2056 | | const gpa = elf.base.comp.gpa; |
| 2401 | const comp = elf.base.comp; |
| 2402 | const gpa = comp.gpa; |
| 2057 | 2403 | try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| 2058 | 2404 | try elf.inputs.ensureUnusedCapacity(gpa, 1); |
| 2059 | 2405 | const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{ |
| ... | ... | @@ -2071,11 +2417,18 @@ fn prelinkInner(elf: *Elf) !void { |
| 2071 | 2417 | .NONE, _ => unreachable, |
| 2072 | 2418 | inline else => |ct_class| { |
| 2073 | 2419 | const ElfN = ct_class.ElfN(); |
| 2420 | const flags: ElfN.Addr = if (elf.options.z_now) std.elf.DF_BIND_NOW else 0; |
| 2421 | const flags_1: ElfN.Addr = if (elf.options.z_now) std.elf.DF_1_NOW else 0; |
| 2074 | 2422 | const needed_len = elf.needed.count(); |
| 2075 | | const dynamic_len = needed_len + @intFromBool(elf.options.soname != null) + 5; |
| 2423 | const dynamic_len = needed_len + @intFromBool(elf.options.soname != null) + |
| 2424 | @intFromBool(flags != 0) + @intFromBool(flags_1 != 0) + |
| 2425 | @intFromBool(comp.config.output_mode == .Exe) + 12; |
| 2076 | 2426 | const dynamic_size: u32 = @intCast(@sizeOf(ElfN.Addr) * 2 * dynamic_len); |
| 2077 | 2427 | const dynamic_ni = elf.si.dynamic.node(elf); |
| 2078 | 2428 | try dynamic_ni.resize(&elf.mf, gpa, dynamic_size); |
| 2429 | switch (elf.shdrPtr(elf.si.dynamic.shndx(elf))) { |
| 2430 | inline else => |shdr| elf.targetStore(&shdr.size, dynamic_size), |
| 2431 | } |
| 2079 | 2432 | const sec_dynamic = dynamic_ni.slice(&elf.mf); |
| 2080 | 2433 | const dynamic_entries: [][2]ElfN.Addr = @ptrCast(@alignCast(sec_dynamic)); |
| 2081 | 2434 | var dynamic_index: usize = 0; |
| ... | ... | @@ -2088,14 +2441,41 @@ fn prelinkInner(elf: *Elf) !void { |
| 2088 | 2441 | dynamic_entries[dynamic_index] = .{ std.elf.DT_SONAME, try elf.string(.dynstr, soname) }; |
| 2089 | 2442 | dynamic_index += 1; |
| 2090 | 2443 | } |
| 2091 | | dynamic_entries[dynamic_index..][0..5].* = .{ |
| 2092 | | .{ std.elf.DT_SYMTAB, 0 }, |
| 2444 | if (flags != 0) { |
| 2445 | dynamic_entries[dynamic_index] = .{ std.elf.DT_FLAGS, flags }; |
| 2446 | dynamic_index += 1; |
| 2447 | } |
| 2448 | if (flags_1 != 0) { |
| 2449 | dynamic_entries[dynamic_index] = .{ std.elf.DT_FLAGS_1, flags_1 }; |
| 2450 | dynamic_index += 1; |
| 2451 | } |
| 2452 | if (comp.config.output_mode == .Exe) { |
| 2453 | dynamic_entries[dynamic_index] = .{ std.elf.DT_DEBUG, 0 }; |
| 2454 | dynamic_index += 1; |
| 2455 | } |
| 2456 | const rela_dyn_si = elf.si.got.shndx(elf).get(elf).rela_si; |
| 2457 | const rela_plt_si = elf.si.got_plt.shndx(elf).get(elf).rela_si; |
| 2458 | dynamic_entries[dynamic_index..][0..12].* = .{ |
| 2459 | .{ std.elf.DT_RELA, @intCast(elf.computeNodeVAddr(rela_dyn_si.node(elf))) }, |
| 2460 | .{ std.elf.DT_RELASZ, elf.targetLoad( |
| 2461 | &@field(elf.shdrPtr(rela_dyn_si.shndx(elf)), @tagName(ct_class)).size, |
| 2462 | ) }, |
| 2463 | .{ std.elf.DT_RELAENT, @sizeOf(ElfN.Rela) }, |
| 2464 | .{ std.elf.DT_JMPREL, @intCast(elf.computeNodeVAddr(rela_plt_si.node(elf))) }, |
| 2465 | .{ std.elf.DT_PLTRELSZ, elf.targetLoad( |
| 2466 | &@field(elf.shdrPtr(rela_plt_si.shndx(elf)), @tagName(ct_class)).size, |
| 2467 | ) }, |
| 2468 | .{ std.elf.DT_PLTGOT, @intCast(elf.computeNodeVAddr(elf.si.got_plt.node(elf))) }, |
| 2469 | .{ std.elf.DT_PLTREL, std.elf.DT_RELA }, |
| 2470 | .{ std.elf.DT_SYMTAB, @intCast(elf.computeNodeVAddr(elf.si.dynsym.node(elf))) }, |
| 2093 | 2471 | .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) }, |
| 2094 | | .{ std.elf.DT_STRTAB, 0 }, |
| 2095 | | .{ std.elf.DT_STRSZ, 0 }, |
| 2472 | .{ std.elf.DT_STRTAB, @intCast(elf.computeNodeVAddr(elf.si.dynstr.node(elf))) }, |
| 2473 | .{ std.elf.DT_STRSZ, elf.targetLoad( |
| 2474 | &@field(elf.shdrPtr(elf.si.dynstr.shndx(elf)), @tagName(ct_class)).size, |
| 2475 | ) }, |
| 2096 | 2476 | .{ std.elf.DT_NULL, 0 }, |
| 2097 | 2477 | }; |
| 2098 | | dynamic_index += 5; |
| 2478 | dynamic_index += 12; |
| 2099 | 2479 | assert(dynamic_index == dynamic_len); |
| 2100 | 2480 | if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry| |
| 2101 | 2481 | std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry); |
| ... | ... | @@ -2103,26 +2483,41 @@ fn prelinkInner(elf: *Elf) !void { |
| 2103 | 2483 | const dynamic_sym = elf.si.dynamic.get(elf); |
| 2104 | 2484 | assert(dynamic_sym.loc_relocs == .none); |
| 2105 | 2485 | dynamic_sym.loc_relocs = @enumFromInt(elf.relocs.items.len); |
| 2106 | | try elf.addReloc( |
| 2486 | try elf.ensureUnusedRelocCapacity(elf.si.dynamic, 5); |
| 2487 | elf.addRelocAssumeCapacity( |
| 2107 | 2488 | elf.si.dynamic, |
| 2108 | | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 5) + 1), |
| 2109 | | elf.si.dynsym, |
| 2489 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 12) + 1), |
| 2490 | rela_dyn_si, |
| 2110 | 2491 | 0, |
| 2111 | 2492 | .absAddr(elf), |
| 2112 | 2493 | ); |
| 2113 | | try elf.addReloc( |
| 2494 | elf.addRelocAssumeCapacity( |
| 2114 | 2495 | elf.si.dynamic, |
| 2115 | | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 3) + 1), |
| 2116 | | elf.si.dynstr, |
| 2496 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 9) + 1), |
| 2497 | rela_plt_si, |
| 2117 | 2498 | 0, |
| 2118 | 2499 | .absAddr(elf), |
| 2119 | 2500 | ); |
| 2120 | | try elf.addReloc( |
| 2501 | elf.addRelocAssumeCapacity( |
| 2121 | 2502 | elf.si.dynamic, |
| 2122 | | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 2) + 1), |
| 2503 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 7) + 1), |
| 2504 | elf.si.got_plt, |
| 2505 | 0, |
| 2506 | .absAddr(elf), |
| 2507 | ); |
| 2508 | elf.addRelocAssumeCapacity( |
| 2509 | elf.si.dynamic, |
| 2510 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 5) + 1), |
| 2511 | elf.si.dynsym, |
| 2512 | 0, |
| 2513 | .absAddr(elf), |
| 2514 | ); |
| 2515 | elf.addRelocAssumeCapacity( |
| 2516 | elf.si.dynamic, |
| 2517 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 3) + 1), |
| 2123 | 2518 | elf.si.dynstr, |
| 2124 | 2519 | 0, |
| 2125 | | .sizeAddr(elf), |
| 2520 | .absAddr(elf), |
| 2126 | 2521 | ); |
| 2127 | 2522 | }, |
| 2128 | 2523 | }; |
| ... | ... | @@ -2168,6 +2563,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 2168 | 2563 | addralign: std.mem.Alignment = .@"1", |
| 2169 | 2564 | entsize: std.elf.Word = 0, |
| 2170 | 2565 | node_align: std.mem.Alignment = .@"1", |
| 2566 | fixed: bool = false, |
| 2171 | 2567 | }) !Symbol.Index { |
| 2172 | 2568 | switch (opts.type) { |
| 2173 | 2569 | .NULL => assert(opts.size == 0), |
| ... | ... | @@ -2215,8 +2611,9 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 2215 | 2611 | .REL => elf.ni.file, |
| 2216 | 2612 | .EXEC, .DYN => segment_ni, |
| 2217 | 2613 | }, .{ |
| 2218 | | .alignment = opts.addralign.max(opts.node_align), |
| 2219 | 2614 | .size = opts.size, |
| 2615 | .alignment = opts.addralign.max(opts.node_align), |
| 2616 | .fixed = opts.fixed, |
| 2220 | 2617 | .resized = opts.size > 0, |
| 2221 | 2618 | }); |
| 2222 | 2619 | const si = elf.addSymbolAssumeCapacity(); |
| ... | ... | @@ -2253,12 +2650,6 @@ fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void { |
| 2253 | 2650 | } |
| 2254 | 2651 | } |
| 2255 | 2652 | |
| 2256 | | fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void { |
| 2257 | | switch (elf.shdrPtr(si.shndx(elf))) { |
| 2258 | | inline else => |shdr| elf.targetStore(&shdr.link, @intFromEnum(link_si.shndx(elf))), |
| 2259 | | } |
| 2260 | | } |
| 2261 | | |
| 2262 | 2653 | fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 { |
| 2263 | 2654 | const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrPtr(si.shndx(elf))) { |
| 2264 | 2655 | inline else => |shdr| elf.targetLoad(&shdr.name), |
| ... | ... | @@ -2285,41 +2676,60 @@ pub fn addReloc( |
| 2285 | 2676 | pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !void { |
| 2286 | 2677 | if (len == 0) return; |
| 2287 | 2678 | const gpa = elf.base.comp.gpa; |
| 2288 | | |
| 2289 | 2679 | try elf.relocs.ensureUnusedCapacity(gpa, len); |
| 2290 | | if (elf.ehdrField(.type) != .REL) return; |
| 2291 | | |
| 2292 | | const shndx = loc_si.shndx(elf); |
| 2293 | | const sh = shndx.get(elf); |
| 2294 | | if (sh.rela_si == .null) { |
| 2295 | | var stack = std.heap.stackFallback(32, gpa); |
| 2296 | | const allocator = stack.get(); |
| 2297 | | |
| 2298 | | const rela_name = try std.fmt.allocPrint(allocator, ".rela{s}", .{elf.sectionName(sh.si)}); |
| 2299 | | defer allocator.free(rela_name); |
| 2300 | | |
| 2301 | | const class = elf.identClass(); |
| 2302 | | sh.rela_si = try elf.addSection(.none, .{ |
| 2303 | | .name = rela_name, |
| 2304 | | .type = .RELA, |
| 2305 | | .link = @intFromEnum(elf.si.symtab.shndx(elf)), |
| 2306 | | .info = @intFromEnum(shndx), |
| 2307 | | .addralign = switch (class) { |
| 2308 | | .NONE, _ => unreachable, |
| 2309 | | .@"32" => .@"4", |
| 2310 | | .@"64" => .@"8", |
| 2311 | | }, |
| 2312 | | .entsize = switch (class) { |
| 2313 | | .NONE, _ => unreachable, |
| 2314 | | inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela), |
| 2315 | | }, |
| 2316 | | .node_align = elf.mf.flags.block_size, |
| 2317 | | }); |
| 2318 | | } |
| 2319 | | const rela_ni = sh.rela_si.node(elf); |
| 2680 | const class = elf.identClass(); |
| 2681 | const rela_si, const rela_len = rela: switch (elf.ehdrField(.type)) { |
| 2682 | .NONE, .CORE, _ => unreachable, |
| 2683 | .REL => { |
| 2684 | const shndx = loc_si.shndx(elf); |
| 2685 | const sh = shndx.get(elf); |
| 2686 | if (sh.rela_si == .null) { |
| 2687 | var stack = std.heap.stackFallback(32, gpa); |
| 2688 | const allocator = stack.get(); |
| 2689 | |
| 2690 | const rela_name = |
| 2691 | try std.fmt.allocPrint(allocator, ".rela{s}", .{elf.sectionName(sh.si)}); |
| 2692 | defer allocator.free(rela_name); |
| 2693 | |
| 2694 | sh.rela_si = try elf.addSection(.none, .{ |
| 2695 | .name = rela_name, |
| 2696 | .type = .RELA, |
| 2697 | .link = @intFromEnum(elf.si.symtab.shndx(elf)), |
| 2698 | .info = @intFromEnum(shndx), |
| 2699 | .addralign = switch (class) { |
| 2700 | .NONE, _ => unreachable, |
| 2701 | .@"32" => .@"4", |
| 2702 | .@"64" => .@"8", |
| 2703 | }, |
| 2704 | .entsize = switch (class) { |
| 2705 | .NONE, _ => unreachable, |
| 2706 | inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela), |
| 2707 | }, |
| 2708 | .node_align = elf.mf.flags.block_size, |
| 2709 | }); |
| 2710 | } |
| 2711 | break :rela .{ sh.rela_si, len }; |
| 2712 | }, |
| 2713 | .EXEC, .DYN => switch (elf.got.tlsld) { |
| 2714 | _ => return, |
| 2715 | .none => if (elf.si.dynamic != .null) { |
| 2716 | try elf.mf.updates.ensureUnusedCapacity(gpa, 1); |
| 2717 | const got_ni = elf.si.got.node(elf); |
| 2718 | _, const got_node_size = got_ni.location(&elf.mf).resolve(&elf.mf); |
| 2719 | const got_size = switch (class) { |
| 2720 | .NONE, _ => unreachable, |
| 2721 | inline else => |ct_class| (elf.got.len + 2) * @sizeOf(ct_class.ElfN().Addr), |
| 2722 | }; |
| 2723 | if (got_size > got_node_size) |
| 2724 | try got_ni.resize(&elf.mf, gpa, got_size +| got_size / MappedFile.growth_factor); |
| 2725 | break :rela .{ elf.si.got.shndx(elf).get(elf).rela_si, 1 }; |
| 2726 | } else return, |
| 2727 | }, |
| 2728 | }; |
| 2729 | const rela_ni = rela_si.node(elf); |
| 2320 | 2730 | _, const rela_node_size = rela_ni.location(&elf.mf).resolve(&elf.mf); |
| 2321 | | const rela_size = switch (elf.shdrPtr(sh.rela_si.shndx(elf))) { |
| 2322 | | inline else => |shdr| elf.targetLoad(&shdr.size) + elf.targetLoad(&shdr.entsize) * len, |
| 2731 | const rela_size = switch (elf.shdrPtr(rela_si.shndx(elf))) { |
| 2732 | inline else => |shdr| elf.targetLoad(&shdr.size) + elf.targetLoad(&shdr.entsize) * rela_len, |
| 2323 | 2733 | }; |
| 2324 | 2734 | if (rela_size > rela_node_size) |
| 2325 | 2735 | try rela_ni.resize(&elf.mf, gpa, rela_size +| rela_size / MappedFile.growth_factor); |
| ... | ... | @@ -2377,7 +2787,59 @@ pub fn addRelocAssumeCapacity( |
| 2377 | 2787 | }, |
| 2378 | 2788 | } |
| 2379 | 2789 | }, |
| 2380 | | .EXEC, .DYN => .none, |
| 2790 | .EXEC, .DYN => { |
| 2791 | switch (elf.ehdrField(.machine)) { |
| 2792 | else => |machine| @panic(@tagName(machine)), |
| 2793 | .AARCH64, .PPC64, .RISCV => {}, |
| 2794 | .X86_64 => switch (@"type".X86_64) { |
| 2795 | else => {}, |
| 2796 | .TLSLD => switch (elf.got.tlsld) { |
| 2797 | _ => {}, |
| 2798 | .none => if (elf.si.dynamic != .null) { |
| 2799 | const tlsld_index = elf.got.len; |
| 2800 | elf.got.tlsld = .wrap(tlsld_index); |
| 2801 | elf.got.len = tlsld_index + 2; |
| 2802 | const got_addr = got_addr: switch (elf.shdrPtr(elf.si.got.shndx(elf))) { |
| 2803 | inline else => |shdr, class| { |
| 2804 | const addr_size = @sizeOf(class.ElfN().Addr); |
| 2805 | const old_size = addr_size * tlsld_index; |
| 2806 | const new_size = old_size + addr_size * 2; |
| 2807 | @memset( |
| 2808 | elf.si.got.node(elf).slice(&elf.mf)[old_size..new_size], |
| 2809 | 0, |
| 2810 | ); |
| 2811 | break :got_addr elf.targetLoad(&shdr.addr) + old_size; |
| 2812 | }, |
| 2813 | }; |
| 2814 | const rela_dyn_si = elf.si.got.shndx(elf).get(elf).rela_si; |
| 2815 | const rela_dyn_ni = rela_dyn_si.node(elf); |
| 2816 | switch (elf.shdrPtr(rela_dyn_si.shndx(elf))) { |
| 2817 | inline else => |shdr, class| { |
| 2818 | const Rela = class.ElfN().Rela; |
| 2819 | const old_size = elf.targetLoad(&shdr.size); |
| 2820 | const new_size = old_size + elf.targetLoad(&shdr.entsize); |
| 2821 | elf.targetStore(&shdr.size, new_size); |
| 2822 | const rela: *Rela = @ptrCast(@alignCast(rela_dyn_ni |
| 2823 | .slice(&elf.mf)[@intCast(old_size)..@intCast(new_size)])); |
| 2824 | rela.* = .{ |
| 2825 | .offset = @intCast(got_addr), |
| 2826 | .info = .{ |
| 2827 | .type = @intFromEnum(std.elf.R_X86_64.DTPMOD64), |
| 2828 | .sym = 0, |
| 2829 | }, |
| 2830 | .addend = 0, |
| 2831 | }; |
| 2832 | if (elf.targetEndian() != native_endian) |
| 2833 | std.mem.byteSwapAllFields(Rela, rela); |
| 2834 | }, |
| 2835 | } |
| 2836 | rela_dyn_ni.resizedAssumeCapacity(&elf.mf); |
| 2837 | }, |
| 2838 | }, |
| 2839 | }, |
| 2840 | } |
| 2841 | break :index .none; |
| 2842 | }, |
| 2381 | 2843 | }, |
| 2382 | 2844 | .offset = offset, |
| 2383 | 2845 | .addend = addend, |
| ... | ... | @@ -2901,7 +3363,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 2901 | 3363 | .NULL, .LOAD => return, |
| 2902 | 3364 | .DYNAMIC, .INTERP => {}, |
| 2903 | 3365 | .PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset, |
| 2904 | | .TLS => {}, |
| 3366 | .TLS, std.elf.PT.GNU_RELRO => {}, |
| 2905 | 3367 | } |
| 2906 | 3368 | elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni))); |
| 2907 | 3369 | ph.paddr = ph.vaddr; |
| ... | ... | @@ -2911,10 +3373,101 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 2911 | 3373 | .section => |si| { |
| 2912 | 3374 | try elf.flushFileOffset(ni); |
| 2913 | 3375 | const addr = elf.computeNodeVAddr(ni); |
| 2914 | | switch (elf.shdrPtr(si.shndx(elf))) { |
| 3376 | const shndx = si.shndx(elf); |
| 3377 | switch (elf.shdrPtr(shndx)) { |
| 2915 | 3378 | inline else => |shdr, class| { |
| 2916 | 3379 | const flags = elf.targetLoad(&shdr.flags).shf; |
| 2917 | 3380 | if (flags.ALLOC) { |
| 3381 | if (elf.si.dynamic != .null) { |
| 3382 | if (si == elf.si.got) { |
| 3383 | const old_addr = elf.targetLoad(&shdr.addr); |
| 3384 | const rela_dyn_si = shndx.get(elf).rela_si; |
| 3385 | const relas: []class.ElfN().Rela = @ptrCast(@alignCast( |
| 3386 | rela_dyn_si.node(elf).slice(&elf.mf)[0..@intCast( |
| 3387 | elf.targetLoad(&@field( |
| 3388 | elf.shdrPtr(rela_dyn_si.shndx(elf)), |
| 3389 | @tagName(class), |
| 3390 | ).size), |
| 3391 | )], |
| 3392 | )); |
| 3393 | switch (elf.ehdrField(.machine)) { |
| 3394 | else => |machine| @panic(@tagName(machine)), |
| 3395 | .AARCH64, .PPC64, .RISCV => {}, |
| 3396 | .X86_64 => for (relas) |*rela| switch (@as( |
| 3397 | std.elf.R_X86_64, |
| 3398 | @enumFromInt(elf.targetLoad(&rela.info).type), |
| 3399 | )) { |
| 3400 | else => |@"type"| @panic(@tagName(@"type")), |
| 3401 | .RELATIVE => {}, |
| 3402 | .GLOB_DAT, .DTPMOD64, .DTPOFF64 => elf.targetStore( |
| 3403 | &rela.offset, |
| 3404 | @intCast(elf.targetLoad(&rela.offset) - old_addr + addr), |
| 3405 | ), |
| 3406 | }, |
| 3407 | } |
| 3408 | } else if (si == elf.si.got_plt) { |
| 3409 | const target_endian = elf.targetEndian(); |
| 3410 | const old_addr = elf.targetLoad(&shdr.addr); |
| 3411 | const rela_plt_si = shndx.get(elf).rela_si; |
| 3412 | const relas: []class.ElfN().Rela = @ptrCast(@alignCast( |
| 3413 | rela_plt_si.node(elf).slice(&elf.mf)[0..@intCast( |
| 3414 | elf.targetLoad(&@field( |
| 3415 | elf.shdrPtr(rela_plt_si.shndx(elf)), |
| 3416 | @tagName(class), |
| 3417 | ).size), |
| 3418 | )], |
| 3419 | )); |
| 3420 | const plt_sec_slice = elf.si.plt_sec.node(elf).slice(&elf.mf); |
| 3421 | switch (elf.ehdrField(.machine)) { |
| 3422 | else => |machine| @panic(@tagName(machine)), |
| 3423 | .AARCH64, .PPC64, .RISCV => {}, |
| 3424 | .X86_64 => { |
| 3425 | for (relas) |*rela| switch (@as( |
| 3426 | std.elf.R_X86_64, |
| 3427 | @enumFromInt(elf.targetLoad(&rela.info).type), |
| 3428 | )) { |
| 3429 | else => |@"type"| @panic(@tagName(@"type")), |
| 3430 | .JUMP_SLOT => elf.targetStore( |
| 3431 | &rela.offset, |
| 3432 | @intCast(elf.targetLoad(&rela.offset) - old_addr + addr), |
| 3433 | ), |
| 3434 | }; |
| 3435 | for (0..elf.got.plt.count()) |plt_index| { |
| 3436 | const slice = plt_sec_slice[16 * plt_index + 6 ..][0..4]; |
| 3437 | std.mem.writeInt( |
| 3438 | i32, |
| 3439 | slice, |
| 3440 | @intCast(@as(i64, @bitCast(@as(u64, @bitCast(@as( |
| 3441 | i64, |
| 3442 | std.mem.readInt(i32, slice, target_endian), |
| 3443 | ))) -% old_addr +% addr))), |
| 3444 | target_endian, |
| 3445 | ); |
| 3446 | } |
| 3447 | }, |
| 3448 | } |
| 3449 | } else if (si == elf.si.plt_sec) { |
| 3450 | const target_endian = elf.targetEndian(); |
| 3451 | const old_addr = elf.targetLoad(&shdr.addr); |
| 3452 | const plt_sec_slice = ni.slice(&elf.mf); |
| 3453 | switch (elf.ehdrField(.machine)) { |
| 3454 | else => |machine| @panic(@tagName(machine)), |
| 3455 | .AARCH64, .PPC64, .RISCV => {}, |
| 3456 | .X86_64 => for (0..elf.got.plt.count()) |plt_index| { |
| 3457 | const slice = plt_sec_slice[16 * plt_index + 6 ..][0..4]; |
| 3458 | std.mem.writeInt( |
| 3459 | i32, |
| 3460 | slice, |
| 3461 | @intCast(@as(i64, @bitCast(@as(u64, @bitCast(@as( |
| 3462 | i64, |
| 3463 | std.mem.readInt(i32, slice, target_endian), |
| 3464 | ))) -% addr +% old_addr))), |
| 3465 | target_endian, |
| 3466 | ); |
| 3467 | }, |
| 3468 | } |
| 3469 | } |
| 3470 | } |
| 2918 | 3471 | elf.targetStore(&shdr.addr, @intCast(addr)); |
| 2919 | 3472 | @field(elf.symPtr(si), @tagName(class)).value = shdr.addr; |
| 2920 | 3473 | } |
| ... | ... | @@ -2960,15 +3513,21 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 2960 | 3513 | const ph = &phdr[phndx]; |
| 2961 | 3514 | elf.targetStore(&ph.filesz, @intCast(size)); |
| 2962 | 3515 | if (size > elf.targetLoad(&ph.memsz)) { |
| 2963 | | const memsz = ni.alignment(&elf.mf).forward(@intCast(size * 4)); |
| 2964 | | elf.targetStore(&ph.memsz, @intCast(memsz)); |
| 2965 | 3516 | switch (elf.targetLoad(&ph.type)) { |
| 2966 | 3517 | else => unreachable, |
| 2967 | 3518 | .NULL => if (size > 0) elf.targetStore(&ph.type, .LOAD), |
| 2968 | 3519 | .LOAD => if (size == 0) elf.targetStore(&ph.type, .NULL), |
| 2969 | | .DYNAMIC, .INTERP, .PHDR => return, |
| 2970 | | .TLS => return ni.childrenMoved(elf.base.comp.gpa, &elf.mf), |
| 3520 | .DYNAMIC, .INTERP, .PHDR, std.elf.PT.GNU_RELRO => { |
| 3521 | elf.targetStore(&ph.memsz, @intCast(size)); |
| 3522 | return; |
| 3523 | }, |
| 3524 | .TLS => { |
| 3525 | elf.targetStore(&ph.memsz, @intCast(size)); |
| 3526 | return ni.childrenMoved(elf.base.comp.gpa, &elf.mf); |
| 3527 | }, |
| 2971 | 3528 | } |
| 3529 | const memsz = ni.alignment(&elf.mf).forward(@intCast(size * 4)); |
| 3530 | elf.targetStore(&ph.memsz, @intCast(memsz)); |
| 2972 | 3531 | var vaddr = elf.targetLoad(&ph.vaddr); |
| 2973 | 3532 | var new_phndx = phndx; |
| 2974 | 3533 | for (phdr[phndx + 1 ..], phndx + 1..) |*next_ph, next_phndx| { |
| ... | ... | @@ -2998,18 +3557,56 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 2998 | 3557 | }, |
| 2999 | 3558 | }, |
| 3000 | 3559 | .section => |si| switch (elf.shdrPtr(si.shndx(elf))) { |
| 3001 | | inline else => |shdr| { |
| 3560 | inline else => |shdr, class| { |
| 3002 | 3561 | switch (elf.targetLoad(&shdr.type)) { |
| 3003 | 3562 | else => unreachable, |
| 3004 | 3563 | .NULL => if (size > 0) elf.targetStore(&shdr.type, .PROGBITS), |
| 3005 | 3564 | .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL), |
| 3006 | | .SYMTAB, .STRTAB, .RELA, .DYNAMIC, .REL, .DYNSYM => return, |
| 3565 | .SYMTAB, .DYNAMIC, .REL, .DYNSYM => return, |
| 3566 | .STRTAB => { |
| 3567 | if (elf.si.dynamic != .null) { |
| 3568 | if (si == elf.si.dynstr) { |
| 3569 | const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast( |
| 3570 | elf.si.dynamic.node(elf).slice(&elf.mf), |
| 3571 | )); |
| 3572 | for (dynamic_entries) |*dynamic_entry| |
| 3573 | switch (elf.targetLoad(&dynamic_entry[0])) { |
| 3574 | else => {}, |
| 3575 | std.elf.DT_STRSZ => dynamic_entry[1] = shdr.size, |
| 3576 | }; |
| 3577 | } |
| 3578 | } |
| 3579 | return; |
| 3580 | }, |
| 3581 | .RELA => { |
| 3582 | if (elf.si.dynamic != .null) { |
| 3583 | if (si == elf.si.got.shndx(elf).get(elf).rela_si) { |
| 3584 | const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast( |
| 3585 | elf.si.dynamic.node(elf).slice(&elf.mf), |
| 3586 | )); |
| 3587 | for (dynamic_entries) |*dynamic_entry| |
| 3588 | switch (elf.targetLoad(&dynamic_entry[0])) { |
| 3589 | else => {}, |
| 3590 | std.elf.DT_RELASZ => dynamic_entry[1] = shdr.size, |
| 3591 | }; |
| 3592 | } else if (si == elf.si.got_plt.shndx(elf).get(elf).rela_si) { |
| 3593 | const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast( |
| 3594 | elf.si.dynamic.node(elf).slice(&elf.mf), |
| 3595 | )); |
| 3596 | for (dynamic_entries) |*dynamic_entry| |
| 3597 | switch (elf.targetLoad(&dynamic_entry[0])) { |
| 3598 | else => {}, |
| 3599 | std.elf.DT_PLTRELSZ => dynamic_entry[1] = shdr.size, |
| 3600 | }; |
| 3601 | } |
| 3602 | } |
| 3603 | return; |
| 3604 | }, |
| 3007 | 3605 | } |
| 3008 | 3606 | elf.targetStore(&shdr.size, @intCast(size)); |
| 3009 | 3607 | }, |
| 3010 | 3608 | }, |
| 3011 | | .input_section => {}, |
| 3012 | | .nav, .uav, .lazy_code, .lazy_const_data => {}, |
| 3609 | .input_section, .nav, .uav, .lazy_code, .lazy_const_data => {}, |
| 3013 | 3610 | } |
| 3014 | 3611 | } |
| 3015 | 3612 | |
| ... | ... | @@ -3069,7 +3666,11 @@ fn updateExportsInner( |
| 3069 | 3666 | while (try elf.idle(pt.tid)) {} |
| 3070 | 3667 | const exported_ni = exported_si.node(elf); |
| 3071 | 3668 | const value, const size, const shndx = switch (elf.symPtr(exported_si)) { |
| 3072 | | inline else => |exported_sym| .{ exported_sym.value, exported_sym.size, exported_sym.shndx }, |
| 3669 | inline else => |exported_sym| .{ |
| 3670 | elf.targetLoad(&exported_sym.value), |
| 3671 | exported_sym.size, |
| 3672 | exported_sym.shndx, |
| 3673 | }, |
| 3073 | 3674 | }; |
| 3074 | 3675 | for (export_indices) |export_index| { |
| 3075 | 3676 | const @"export" = export_index.ptr(zcu); |
| ... | ... | @@ -3092,18 +3693,11 @@ fn updateExportsInner( |
| 3092 | 3693 | export_si.get(elf).ni = exported_ni; |
| 3093 | 3694 | switch (elf.symPtr(export_si)) { |
| 3094 | 3695 | inline else => |export_sym| { |
| 3095 | | export_sym.value = @intCast(value); |
| 3096 | 3696 | export_sym.size = @intCast(size); |
| 3097 | 3697 | export_sym.shndx = shndx; |
| 3098 | 3698 | }, |
| 3099 | 3699 | } |
| 3100 | | export_si.applyTargetRelocs(elf); |
| 3101 | | if (std.mem.eql(u8, name, "_start")) { |
| 3102 | | elf.entry_hack = exported_si; |
| 3103 | | switch (elf.ehdrPtr()) { |
| 3104 | | inline else => |ehdr| ehdr.entry = @intCast(value), |
| 3105 | | } |
| 3106 | | } |
| 3700 | export_si.flushMoved(elf, value); |
| 3107 | 3701 | } |
| 3108 | 3702 | } |
| 3109 | 3703 | |