| author | |
| committer | |
| log | 6fd1c64f23807993246515b93eb14978cff0e5da |
| tree | b6e218e5eae869258f5b51e1a105f52df60d62be |
| parent | f8b38a174f0c4a843688fe8adac09dc4f66cd585 |
| parent | ea3f1d27e0145a279f1920ccd8dc9b81c02f15bc |
| signature |
x86_64+elf: TLS support11 files changed, 349 insertions(+), 132 deletions(-)
lib/std/math/big/int_test.zig+3| ... | @@ -1443,6 +1443,9 @@ test "big.int divFloor #11166" { | ... | @@ -1443,6 +1443,9 @@ test "big.int divFloor #11166" { |
| 1443 | } | 1443 | } |
| 1444 | 1444 | ||
| 1445 | test "big.int gcd #10932" { | 1445 | test "big.int gcd #10932" { |
| 1446 | // TODO https://github.com/ziglang/zig/issues/17998 | ||
| 1447 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 1448 | |||
| 1446 | var a = try Managed.init(testing.allocator); | 1449 | var a = try Managed.init(testing.allocator); |
| 1447 | defer a.deinit(); | 1450 | defer a.deinit(); |
| 1448 | 1451 |
src/arch/x86_64/CodeGen.zig+46-34| ... | @@ -1107,6 +1107,7 @@ fn formatWipMir( | ... | @@ -1107,6 +1107,7 @@ fn formatWipMir( |
| 1107 | .cc = .Unspecified, | 1107 | .cc = .Unspecified, |
| 1108 | .src_loc = data.self.src_loc, | 1108 | .src_loc = data.self.src_loc, |
| 1109 | }; | 1109 | }; |
| 1110 | var first = true; | ||
| 1110 | for ((lower.lowerMir(data.inst) catch |err| switch (err) { | 1111 | for ((lower.lowerMir(data.inst) catch |err| switch (err) { |
| 1111 | error.LowerFail => { | 1112 | error.LowerFail => { |
| 1112 | defer { | 1113 | defer { |
| ... | @@ -1125,7 +1126,11 @@ fn formatWipMir( | ... | @@ -1125,7 +1126,11 @@ fn formatWipMir( |
| 1125 | return; | 1126 | return; |
| 1126 | }, | 1127 | }, |
| 1127 | else => |e| return e, | 1128 | else => |e| return e, |
| 1128 | }).insts) |lowered_inst| try writer.print(" | {}", .{lowered_inst}); | 1129 | }).insts) |lowered_inst| { |
| 1130 | if (!first) try writer.writeAll("\ndebug(wip_mir): "); | ||
| 1131 | try writer.print(" | {}", .{lowered_inst}); | ||
| 1132 | first = false; | ||
| 1133 | } | ||
| 1129 | } | 1134 | } |
| 1130 | fn fmtWipMir(self: *Self, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir) { | 1135 | fn fmtWipMir(self: *Self, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir) { |
| 1131 | return .{ .data = .{ .self = self, .inst = inst } }; | 1136 | return .{ .data = .{ .self = self, .inst = inst } }; |
| ... | @@ -10802,7 +10807,6 @@ fn genCall(self: *Self, info: union(enum) { | ... | @@ -10802,7 +10807,6 @@ fn genCall(self: *Self, info: union(enum) { |
| 10802 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | 10807 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 10803 | const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl); | 10808 | const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl); |
| 10804 | const sym = elf_file.symbol(sym_index); | 10809 | const sym = elf_file.symbol(sym_index); |
| 10805 | sym.flags.needs_zig_got = true; | ||
| 10806 | if (self.bin_file.options.pic) { | 10810 | if (self.bin_file.options.pic) { |
| 10807 | const callee_reg: Register = switch (resolved_cc) { | 10811 | const callee_reg: Register = switch (resolved_cc) { |
| 10808 | .SysV => callee: { | 10812 | .SysV => callee: { |
| ... | @@ -13382,35 +13386,25 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -13382,35 +13386,25 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 13382 | }, | 13386 | }, |
| 13383 | .lea_direct, .lea_got => |sym_index| { | 13387 | .lea_direct, .lea_got => |sym_index| { |
| 13384 | const atom_index = try self.owner.getSymbolIndex(self); | 13388 | const atom_index = try self.owner.getSymbolIndex(self); |
| 13385 | if (self.bin_file.cast(link.File.Elf)) |_| { | 13389 | _ = try self.addInst(.{ |
| 13386 | try self.asmRegisterMemory(.{ ._, .lea }, dst_reg.to64(), .{ | 13390 | .tag = switch (src_mcv) { |
| 13387 | .base = .{ .reloc = .{ | 13391 | .lea_direct => .lea, |
| 13392 | .lea_got => .mov, | ||
| 13393 | else => unreachable, | ||
| 13394 | }, | ||
| 13395 | .ops = switch (src_mcv) { | ||
| 13396 | .lea_direct => .direct_reloc, | ||
| 13397 | .lea_got => .got_reloc, | ||
| 13398 | else => unreachable, | ||
| 13399 | }, | ||
| 13400 | .data = .{ .rx = .{ | ||
| 13401 | .r1 = dst_reg.to64(), | ||
| 13402 | .payload = try self.addExtra(bits.Symbol{ | ||
| 13388 | .atom_index = atom_index, | 13403 | .atom_index = atom_index, |
| 13389 | .sym_index = sym_index, | 13404 | .sym_index = sym_index, |
| 13390 | } }, | 13405 | }), |
| 13391 | .mod = .{ .rm = .{ .size = .qword } }, | 13406 | } }, |
| 13392 | }); | 13407 | }); |
| 13393 | } else { | ||
| 13394 | _ = try self.addInst(.{ | ||
| 13395 | .tag = switch (src_mcv) { | ||
| 13396 | .lea_direct => .lea, | ||
| 13397 | .lea_got => .mov, | ||
| 13398 | else => unreachable, | ||
| 13399 | }, | ||
| 13400 | .ops = switch (src_mcv) { | ||
| 13401 | .lea_direct => .direct_reloc, | ||
| 13402 | .lea_got => .got_reloc, | ||
| 13403 | else => unreachable, | ||
| 13404 | }, | ||
| 13405 | .data = .{ .rx = .{ | ||
| 13406 | .r1 = dst_reg.to64(), | ||
| 13407 | .payload = try self.addExtra(bits.Symbol{ | ||
| 13408 | .atom_index = atom_index, | ||
| 13409 | .sym_index = sym_index, | ||
| 13410 | }), | ||
| 13411 | } }, | ||
| 13412 | }); | ||
| 13413 | } | ||
| 13414 | }, | 13408 | }, |
| 13415 | .lea_tlv => |sym_index| { | 13409 | .lea_tlv => |sym_index| { |
| 13416 | const atom_index = try self.owner.getSymbolIndex(self); | 13410 | const atom_index = try self.owner.getSymbolIndex(self); |
| ... | @@ -13690,7 +13684,6 @@ fn genLazySymbolRef( | ... | @@ -13690,7 +13684,6 @@ fn genLazySymbolRef( |
| 13690 | const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, lazy_sym) catch |err| | 13684 | const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, lazy_sym) catch |err| |
| 13691 | return self.fail("{s} creating lazy symbol", .{@errorName(err)}); | 13685 | return self.fail("{s} creating lazy symbol", .{@errorName(err)}); |
| 13692 | const sym = elf_file.symbol(sym_index); | 13686 | const sym = elf_file.symbol(sym_index); |
| 13693 | sym.flags.needs_zig_got = true; | ||
| 13694 | if (self.bin_file.options.pic) { | 13687 | if (self.bin_file.options.pic) { |
| 13695 | switch (tag) { | 13688 | switch (tag) { |
| 13696 | .lea, .call => try self.genSetReg(reg, Type.usize, .{ | 13689 | .lea, .call => try self.genSetReg(reg, Type.usize, .{ |
| ... | @@ -15810,11 +15803,30 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { | ... | @@ -15810,11 +15803,30 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { |
| 15810 | } else mcv: { | 15803 | } else mcv: { |
| 15811 | const ip_index = Air.refToInterned(ref).?; | 15804 | const ip_index = Air.refToInterned(ref).?; |
| 15812 | const gop = try self.const_tracking.getOrPut(self.gpa, ip_index); | 15805 | const gop = try self.const_tracking.getOrPut(self.gpa, ip_index); |
| 15813 | const mcv = try self.genTypedValue(.{ | 15806 | if (!gop.found_existing) gop.value_ptr.* = InstTracking.init(init: { |
| 15814 | .ty = ty, | 15807 | const const_mcv = try self.genTypedValue(.{ .ty = ty, .val = ip_index.toValue() }); |
| 15815 | .val = ip_index.toValue(), | 15808 | switch (const_mcv) { |
| 15809 | .lea_tlv => |tlv_sym| if (self.bin_file.cast(link.File.Elf)) |_| { | ||
| 15810 | if (self.bin_file.options.pic) { | ||
| 15811 | try self.spillRegisters(&.{ .rdi, .rax }); | ||
| 15812 | } else { | ||
| 15813 | try self.spillRegisters(&.{.rax}); | ||
| 15814 | } | ||
| 15815 | const frame_index = try self.allocFrameIndex(FrameAlloc.init(.{ | ||
| 15816 | .size = 8, | ||
| 15817 | .alignment = .@"8", | ||
| 15818 | })); | ||
| 15819 | try self.genSetMem( | ||
| 15820 | .{ .frame = frame_index }, | ||
| 15821 | 0, | ||
| 15822 | Type.usize, | ||
| 15823 | .{ .lea_symbol = .{ .sym = tlv_sym } }, | ||
| 15824 | ); | ||
| 15825 | break :init .{ .load_frame = .{ .index = frame_index } }; | ||
| 15826 | } else break :init const_mcv, | ||
| 15827 | else => break :init const_mcv, | ||
| 15828 | } | ||
| 15816 | }); | 15829 | }); |
| 15817 | if (!gop.found_existing) gop.value_ptr.* = InstTracking.init(mcv); | ||
| 15818 | break :mcv gop.value_ptr.short; | 15830 | break :mcv gop.value_ptr.short; |
| 15819 | }; | 15831 | }; |
| 15820 | 15832 |
src/arch/x86_64/Emit.zig+20| ... | @@ -84,6 +84,24 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -84,6 +84,24 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 84 | } else return emit.fail("TODO implement extern reloc for {s}", .{ | 84 | } else return emit.fail("TODO implement extern reloc for {s}", .{ |
| 85 | @tagName(emit.lower.bin_file.tag), | 85 | @tagName(emit.lower.bin_file.tag), |
| 86 | }), | 86 | }), |
| 87 | .linker_tlsld => |data| { | ||
| 88 | const elf_file = emit.lower.bin_file.cast(link.File.Elf).?; | ||
| 89 | const atom = elf_file.symbol(data.atom_index).atom(elf_file).?; | ||
| 90 | try atom.addReloc(elf_file, .{ | ||
| 91 | .r_offset = end_offset - 4, | ||
| 92 | .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | std.elf.R_X86_64_TLSLD, | ||
| 93 | .r_addend = -4, | ||
| 94 | }); | ||
| 95 | }, | ||
| 96 | .linker_dtpoff => |data| { | ||
| 97 | const elf_file = emit.lower.bin_file.cast(link.File.Elf).?; | ||
| 98 | const atom = elf_file.symbol(data.atom_index).atom(elf_file).?; | ||
| 99 | try atom.addReloc(elf_file, .{ | ||
| 100 | .r_offset = end_offset - 4, | ||
| 101 | .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | std.elf.R_X86_64_DTPOFF32, | ||
| 102 | .r_addend = 0, | ||
| 103 | }); | ||
| 104 | }, | ||
| 87 | .linker_reloc => |data| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| { | 105 | .linker_reloc => |data| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| { |
| 88 | const is_obj_or_static_lib = switch (emit.lower.bin_file.options.output_mode) { | 106 | const is_obj_or_static_lib = switch (emit.lower.bin_file.options.output_mode) { |
| 89 | .Exe => false, | 107 | .Exe => false, |
| ... | @@ -120,6 +138,8 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -120,6 +138,8 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 120 | link.File.Elf.R_X86_64_ZIG_GOT32 | 138 | link.File.Elf.R_X86_64_ZIG_GOT32 |
| 121 | else if (sym.flags.needs_got) | 139 | else if (sym.flags.needs_got) |
| 122 | std.elf.R_X86_64_GOT32 | 140 | std.elf.R_X86_64_GOT32 |
| 141 | else if (sym.flags.is_tls) | ||
| 142 | std.elf.R_X86_64_TPOFF32 | ||
| 123 | else | 143 | else |
| 124 | std.elf.R_X86_64_32; | 144 | std.elf.R_X86_64_32; |
| 125 | try atom.addReloc(elf_file, .{ | 145 | try atom.addReloc(elf_file, .{ |
src/arch/x86_64/Lower.zig+64-8| ... | @@ -11,6 +11,7 @@ result_relocs_len: u8 = undefined, | ... | @@ -11,6 +11,7 @@ result_relocs_len: u8 = undefined, |
| 11 | result_insts: [ | 11 | result_insts: [ |
| 12 | std.mem.max(usize, &.{ | 12 | std.mem.max(usize, &.{ |
| 13 | 1, // non-pseudo instructions | 13 | 1, // non-pseudo instructions |
| 14 | 3, // TLS local dynamic (LD) sequence in PIC mode | ||
| 14 | 2, // cmovcc: cmovcc \ cmovcc | 15 | 2, // cmovcc: cmovcc \ cmovcc |
| 15 | 3, // setcc: setcc \ setcc \ logicop | 16 | 3, // setcc: setcc \ setcc \ logicop |
| 16 | 2, // jcc: jcc \ jcc | 17 | 2, // jcc: jcc \ jcc |
| ... | @@ -28,6 +29,7 @@ result_relocs: [ | ... | @@ -28,6 +29,7 @@ result_relocs: [ |
| 28 | 2, // jcc: jcc \ jcc | 29 | 2, // jcc: jcc \ jcc |
| 29 | 2, // test \ jcc \ probe \ sub \ jmp | 30 | 2, // test \ jcc \ probe \ sub \ jmp |
| 30 | 1, // probe \ sub \ jcc | 31 | 1, // probe \ sub \ jcc |
| 32 | 3, // TLS local dynamic (LD) sequence in PIC mode | ||
| 31 | }) | 33 | }) |
| 32 | ]Reloc = undefined, | 34 | ]Reloc = undefined, |
| 33 | 35 | ||
| ... | @@ -51,6 +53,8 @@ pub const Reloc = struct { | ... | @@ -51,6 +53,8 @@ pub const Reloc = struct { |
| 51 | const Target = union(enum) { | 53 | const Target = union(enum) { |
| 52 | inst: Mir.Inst.Index, | 54 | inst: Mir.Inst.Index, |
| 53 | linker_reloc: bits.Symbol, | 55 | linker_reloc: bits.Symbol, |
| 56 | linker_tlsld: bits.Symbol, | ||
| 57 | linker_dtpoff: bits.Symbol, | ||
| 54 | linker_extern_fn: bits.Symbol, | 58 | linker_extern_fn: bits.Symbol, |
| 55 | linker_got: bits.Symbol, | 59 | linker_got: bits.Symbol, |
| 56 | linker_direct: bits.Symbol, | 60 | linker_direct: bits.Symbol, |
| ... | @@ -319,20 +323,25 @@ fn reloc(lower: *Lower, target: Reloc.Target) Immediate { | ... | @@ -319,20 +323,25 @@ fn reloc(lower: *Lower, target: Reloc.Target) Immediate { |
| 319 | return Immediate.s(0); | 323 | return Immediate.s(0); |
| 320 | } | 324 | } |
| 321 | 325 | ||
| 322 | fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void { | 326 | fn needsZigGot(sym: bits.Symbol, ctx: *link.File) bool { |
| 323 | const needsZigGot = struct { | 327 | const elf_file = ctx.cast(link.File.Elf).?; |
| 324 | fn needsZigGot(sym: bits.Symbol, ctx: *link.File) bool { | 328 | const sym_index = elf_file.zigObjectPtr().?.symbol(sym.sym_index); |
| 325 | const elf_file = ctx.cast(link.File.Elf).?; | 329 | return elf_file.symbol(sym_index).flags.needs_zig_got; |
| 326 | const sym_index = elf_file.zigObjectPtr().?.symbol(sym.sym_index); | 330 | } |
| 327 | return elf_file.symbol(sym_index).flags.needs_zig_got; | 331 | |
| 328 | } | 332 | fn isTls(sym: bits.Symbol, ctx: *link.File) bool { |
| 329 | }.needsZigGot; | 333 | const elf_file = ctx.cast(link.File.Elf).?; |
| 334 | const sym_index = elf_file.zigObjectPtr().?.symbol(sym.sym_index); | ||
| 335 | return elf_file.symbol(sym_index).flags.is_tls; | ||
| 336 | } | ||
| 330 | 337 | ||
| 338 | fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void { | ||
| 331 | const is_obj_or_static_lib = switch (lower.bin_file.options.output_mode) { | 339 | const is_obj_or_static_lib = switch (lower.bin_file.options.output_mode) { |
| 332 | .Exe => false, | 340 | .Exe => false, |
| 333 | .Obj => true, | 341 | .Obj => true, |
| 334 | .Lib => lower.bin_file.options.link_mode == .Static, | 342 | .Lib => lower.bin_file.options.link_mode == .Static, |
| 335 | }; | 343 | }; |
| 344 | |||
| 336 | var emit_prefix = prefix; | 345 | var emit_prefix = prefix; |
| 337 | var emit_mnemonic = mnemonic; | 346 | var emit_mnemonic = mnemonic; |
| 338 | var emit_ops_storage: [4]Operand = undefined; | 347 | var emit_ops_storage: [4]Operand = undefined; |
| ... | @@ -346,6 +355,53 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) | ... | @@ -346,6 +355,53 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 346 | assert(prefix == .none); | 355 | assert(prefix == .none); |
| 347 | assert(mem_op.sib.disp == 0); | 356 | assert(mem_op.sib.disp == 0); |
| 348 | assert(mem_op.sib.scale_index.scale == 0); | 357 | assert(mem_op.sib.scale_index.scale == 0); |
| 358 | |||
| 359 | if (isTls(sym, lower.bin_file)) { | ||
| 360 | // TODO handle extern TLS vars, i.e., emit GD model | ||
| 361 | if (lower.bin_file.options.pic) { | ||
| 362 | // Here, we currently assume local dynamic TLS vars, and so | ||
| 363 | // we emit LD model. | ||
| 364 | _ = lower.reloc(.{ .linker_tlsld = sym }); | ||
| 365 | lower.result_insts[lower.result_insts_len] = | ||
| 366 | try Instruction.new(.none, .lea, &[_]Operand{ | ||
| 367 | .{ .reg = .rdi }, | ||
| 368 | .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }, | ||
| 369 | }); | ||
| 370 | lower.result_insts_len += 1; | ||
| 371 | if (lower.bin_file.cast(link.File.Elf)) |elf_file| { | ||
| 372 | _ = lower.reloc(.{ .linker_extern_fn = .{ | ||
| 373 | .atom_index = sym.atom_index, | ||
| 374 | .sym_index = try elf_file.getGlobalSymbol("__tls_get_addr", null), | ||
| 375 | } }); | ||
| 376 | } | ||
| 377 | lower.result_insts[lower.result_insts_len] = | ||
| 378 | try Instruction.new(.none, .call, &[_]Operand{ | ||
| 379 | .{ .imm = Immediate.s(0) }, | ||
| 380 | }); | ||
| 381 | lower.result_insts_len += 1; | ||
| 382 | _ = lower.reloc(.{ .linker_dtpoff = sym }); | ||
| 383 | emit_mnemonic = .lea; | ||
| 384 | break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ | ||
| 385 | .base = .{ .reg = .rax }, | ||
| 386 | .disp = std.math.minInt(i32), | ||
| 387 | }) }; | ||
| 388 | } else { | ||
| 389 | // Since we are linking statically, we emit LE model directly. | ||
| 390 | lower.result_insts[lower.result_insts_len] = | ||
| 391 | try Instruction.new(.none, .mov, &[_]Operand{ | ||
| 392 | .{ .reg = .rax }, | ||
| 393 | .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .fs } }) }, | ||
| 394 | }); | ||
| 395 | lower.result_insts_len += 1; | ||
| 396 | _ = lower.reloc(.{ .linker_reloc = sym }); | ||
| 397 | emit_mnemonic = .lea; | ||
| 398 | break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ | ||
| 399 | .base = .{ .reg = .rax }, | ||
| 400 | .disp = std.math.minInt(i32), | ||
| 401 | }) }; | ||
| 402 | } | ||
| 403 | } | ||
| 404 | |||
| 349 | _ = lower.reloc(.{ .linker_reloc = sym }); | 405 | _ = lower.reloc(.{ .linker_reloc = sym }); |
| 350 | break :op if (lower.bin_file.options.pic) switch (mnemonic) { | 406 | break :op if (lower.bin_file.options.pic) switch (mnemonic) { |
| 351 | .lea => { | 407 | .lea => { |
src/codegen.zig+3-1| ... | @@ -912,7 +912,9 @@ fn genDeclRef( | ... | @@ -912,7 +912,9 @@ fn genDeclRef( |
| 912 | } | 912 | } |
| 913 | const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index); | 913 | const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index); |
| 914 | const sym = elf_file.symbol(sym_index); | 914 | const sym = elf_file.symbol(sym_index); |
| 915 | sym.flags.needs_zig_got = true; | 915 | if (is_threadlocal) { |
| 916 | return GenResult.mcv(.{ .load_tlv = sym.esym_index }); | ||
| 917 | } | ||
| 916 | return GenResult.mcv(.{ .load_symbol = sym.esym_index }); | 918 | return GenResult.mcv(.{ .load_symbol = sym.esym_index }); |
| 917 | } else if (bin_file.cast(link.File.MachO)) |macho_file| { | 919 | } else if (bin_file.cast(link.File.MachO)) |macho_file| { |
| 918 | if (is_extern) { | 920 | if (is_extern) { |
src/link/Coff.zig+4-4| ... | @@ -388,7 +388,6 @@ fn populateMissingMetadata(self: *Coff) !void { | ... | @@ -388,7 +388,6 @@ fn populateMissingMetadata(self: *Coff) !void { |
| 388 | self.rdata_section_index = try self.allocateSection(".rdata", file_size, .{ | 388 | self.rdata_section_index = try self.allocateSection(".rdata", file_size, .{ |
| 389 | .CNT_INITIALIZED_DATA = 1, | 389 | .CNT_INITIALIZED_DATA = 1, |
| 390 | .MEM_READ = 1, | 390 | .MEM_READ = 1, |
| 391 | .MEM_WRITE = 1, | ||
| 392 | }); | 391 | }); |
| 393 | } | 392 | } |
| 394 | 393 | ||
| ... | @@ -920,7 +919,7 @@ fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void { | ... | @@ -920,7 +919,7 @@ fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void { |
| 920 | fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void { | 919 | fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void { |
| 921 | const got_moved = blk: { | 920 | const got_moved = blk: { |
| 922 | const sect_id = self.got_section_index orelse break :blk false; | 921 | const sect_id = self.got_section_index orelse break :blk false; |
| 923 | break :blk self.sections.items(.header)[sect_id].virtual_address > addr; | 922 | break :blk self.sections.items(.header)[sect_id].virtual_address >= addr; |
| 924 | }; | 923 | }; |
| 925 | 924 | ||
| 926 | // TODO: dirty relocations targeting import table if that got moved in memory | 925 | // TODO: dirty relocations targeting import table if that got moved in memory |
| ... | @@ -931,7 +930,7 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void { | ... | @@ -931,7 +930,7 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void { |
| 931 | reloc.dirty = reloc.dirty or got_moved; | 930 | reloc.dirty = reloc.dirty or got_moved; |
| 932 | } else { | 931 | } else { |
| 933 | const target_vaddr = reloc.getTargetAddress(self) orelse continue; | 932 | const target_vaddr = reloc.getTargetAddress(self) orelse continue; |
| 934 | if (target_vaddr > addr) reloc.dirty = true; | 933 | if (target_vaddr >= addr) reloc.dirty = true; |
| 935 | } | 934 | } |
| 936 | } | 935 | } |
| 937 | } | 936 | } |
| ... | @@ -939,7 +938,7 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void { | ... | @@ -939,7 +938,7 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void { |
| 939 | // TODO: dirty only really affected GOT cells | 938 | // TODO: dirty only really affected GOT cells |
| 940 | for (self.got_table.entries.items) |entry| { | 939 | for (self.got_table.entries.items) |entry| { |
| 941 | const target_addr = self.getSymbol(entry).value; | 940 | const target_addr = self.getSymbol(entry).value; |
| 942 | if (target_addr > addr) { | 941 | if (target_addr >= addr) { |
| 943 | self.got_table_contents_dirty = true; | 942 | self.got_table_contents_dirty = true; |
| 944 | break; | 943 | break; |
| 945 | } | 944 | } |
| ... | @@ -1722,6 +1721,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -1722,6 +1721,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1722 | var code = std.ArrayList(u8).init(gpa); | 1721 | var code = std.ArrayList(u8).init(gpa); |
| 1723 | defer code.deinit(); | 1722 | defer code.deinit(); |
| 1724 | try code.resize(math.cast(usize, atom.size) orelse return error.Overflow); | 1723 | try code.resize(math.cast(usize, atom.size) orelse return error.Overflow); |
| 1724 | assert(atom.size > 0); | ||
| 1725 | 1725 | ||
| 1726 | const amt = try self.base.file.?.preadAll(code.items, file_offset); | 1726 | const amt = try self.base.file.?.preadAll(code.items, file_offset); |
| 1727 | if (amt != code.items.len) return error.InputOutput; | 1727 | if (amt != code.items.len) return error.InputOutput; |
src/link/Elf.zig+23-7| ... | @@ -4512,7 +4512,10 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { | ... | @@ -4512,7 +4512,10 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { |
| 4512 | 4512 | ||
| 4513 | for (cover.items) |shndx| { | 4513 | for (cover.items) |shndx| { |
| 4514 | const shdr = &self.shdrs.items[shndx]; | 4514 | const shdr = &self.shdrs.items[shndx]; |
| 4515 | if (shdr.sh_type == elf.SHT_NOBITS) continue; | 4515 | if (shdr.sh_type == elf.SHT_NOBITS) { |
| 4516 | shdr.sh_offset = 0; | ||
| 4517 | continue; | ||
| 4518 | } | ||
| 4516 | off = alignment.@"align"(shndx, shdr.sh_addralign, off); | 4519 | off = alignment.@"align"(shndx, shdr.sh_addralign, off); |
| 4517 | shdr.sh_offset = off; | 4520 | shdr.sh_offset = off; |
| 4518 | off += shdr.sh_size; | 4521 | off += shdr.sh_size; |
| ... | @@ -4528,7 +4531,10 @@ fn allocateAllocSectionsObject(self: *Elf) !void { | ... | @@ -4528,7 +4531,10 @@ fn allocateAllocSectionsObject(self: *Elf) !void { |
| 4528 | for (self.shdrs.items) |*shdr| { | 4531 | for (self.shdrs.items) |*shdr| { |
| 4529 | if (shdr.sh_type == elf.SHT_NULL) continue; | 4532 | if (shdr.sh_type == elf.SHT_NULL) continue; |
| 4530 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; | 4533 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; |
| 4531 | if (shdr.sh_type == elf.SHT_NOBITS) continue; | 4534 | if (shdr.sh_type == elf.SHT_NOBITS) { |
| 4535 | shdr.sh_offset = 0; | ||
| 4536 | continue; | ||
| 4537 | } | ||
| 4532 | const needed_size = shdr.sh_size; | 4538 | const needed_size = shdr.sh_size; |
| 4533 | if (needed_size > self.allocatedSize(shdr.sh_offset)) { | 4539 | if (needed_size > self.allocatedSize(shdr.sh_offset)) { |
| 4534 | shdr.sh_size = 0; | 4540 | shdr.sh_size = 0; |
| ... | @@ -4640,6 +4646,9 @@ fn allocateSpecialPhdrs(self: *Elf) void { | ... | @@ -4640,6 +4646,9 @@ fn allocateSpecialPhdrs(self: *Elf) void { |
| 4640 | } | 4646 | } |
| 4641 | 4647 | ||
| 4642 | fn allocateAtoms(self: *Elf) void { | 4648 | fn allocateAtoms(self: *Elf) void { |
| 4649 | if (self.zigObjectPtr()) |zig_object| { | ||
| 4650 | zig_object.allocateTlvAtoms(self); | ||
| 4651 | } | ||
| 4643 | for (self.objects.items) |index| { | 4652 | for (self.objects.items) |index| { |
| 4644 | self.file(index).?.object.allocateAtoms(self); | 4653 | self.file(index).?.object.allocateAtoms(self); |
| 4645 | } | 4654 | } |
| ... | @@ -4698,7 +4707,6 @@ fn writeAtoms(self: *Elf) !void { | ... | @@ -4698,7 +4707,6 @@ fn writeAtoms(self: *Elf) !void { |
| 4698 | const atom_ptr = self.atom(atom_index).?; | 4707 | const atom_ptr = self.atom(atom_index).?; |
| 4699 | assert(atom_ptr.flags.alive); | 4708 | assert(atom_ptr.flags.alive); |
| 4700 | 4709 | ||
| 4701 | const object = atom_ptr.file(self).?.object; | ||
| 4702 | const offset = math.cast(usize, atom_ptr.value - shdr.sh_addr - base_offset) orelse | 4710 | const offset = math.cast(usize, atom_ptr.value - shdr.sh_addr - base_offset) orelse |
| 4703 | return error.Overflow; | 4711 | return error.Overflow; |
| 4704 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; | 4712 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; |
| ... | @@ -4707,7 +4715,11 @@ fn writeAtoms(self: *Elf) !void { | ... | @@ -4707,7 +4715,11 @@ fn writeAtoms(self: *Elf) !void { |
| 4707 | 4715 | ||
| 4708 | // TODO decompress directly into provided buffer | 4716 | // TODO decompress directly into provided buffer |
| 4709 | const out_code = buffer[offset..][0..size]; | 4717 | const out_code = buffer[offset..][0..size]; |
| 4710 | const in_code = try object.codeDecompressAlloc(self, atom_index); | 4718 | const in_code = switch (atom_ptr.file(self).?) { |
| 4719 | .object => |x| try x.codeDecompressAlloc(self, atom_index), | ||
| 4720 | .zig_object => |x| try x.codeAlloc(self, atom_index), | ||
| 4721 | else => unreachable, | ||
| 4722 | }; | ||
| 4711 | defer gpa.free(in_code); | 4723 | defer gpa.free(in_code); |
| 4712 | @memcpy(out_code, in_code); | 4724 | @memcpy(out_code, in_code); |
| 4713 | 4725 | ||
| ... | @@ -4774,7 +4786,6 @@ fn writeAtomsObject(self: *Elf) !void { | ... | @@ -4774,7 +4786,6 @@ fn writeAtomsObject(self: *Elf) !void { |
| 4774 | const atom_ptr = self.atom(atom_index).?; | 4786 | const atom_ptr = self.atom(atom_index).?; |
| 4775 | assert(atom_ptr.flags.alive); | 4787 | assert(atom_ptr.flags.alive); |
| 4776 | 4788 | ||
| 4777 | const object = atom_ptr.file(self).?.object; | ||
| 4778 | const offset = math.cast(usize, atom_ptr.value - shdr.sh_addr - base_offset) orelse | 4789 | const offset = math.cast(usize, atom_ptr.value - shdr.sh_addr - base_offset) orelse |
| 4779 | return error.Overflow; | 4790 | return error.Overflow; |
| 4780 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; | 4791 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; |
| ... | @@ -4787,7 +4798,11 @@ fn writeAtomsObject(self: *Elf) !void { | ... | @@ -4787,7 +4798,11 @@ fn writeAtomsObject(self: *Elf) !void { |
| 4787 | 4798 | ||
| 4788 | // TODO decompress directly into provided buffer | 4799 | // TODO decompress directly into provided buffer |
| 4789 | const out_code = buffer[offset..][0..size]; | 4800 | const out_code = buffer[offset..][0..size]; |
| 4790 | const in_code = try object.codeDecompressAlloc(self, atom_index); | 4801 | const in_code = switch (atom_ptr.file(self).?) { |
| 4802 | .object => |x| try x.codeDecompressAlloc(self, atom_index), | ||
| 4803 | .zig_object => |x| try x.codeAlloc(self, atom_index), | ||
| 4804 | else => unreachable, | ||
| 4805 | }; | ||
| 4791 | defer gpa.free(in_code); | 4806 | defer gpa.free(in_code); |
| 4792 | @memcpy(out_code, in_code); | 4807 | @memcpy(out_code, in_code); |
| 4793 | } | 4808 | } |
| ... | @@ -6250,8 +6265,9 @@ fn fmtDumpState( | ... | @@ -6250,8 +6265,9 @@ fn fmtDumpState( |
| 6250 | try writer.print("linker_defined({d}) : (linker defined)\n", .{index}); | 6265 | try writer.print("linker_defined({d}) : (linker defined)\n", .{index}); |
| 6251 | try writer.print("{}\n", .{linker_defined.fmtSymtab(self)}); | 6266 | try writer.print("{}\n", .{linker_defined.fmtSymtab(self)}); |
| 6252 | } | 6267 | } |
| 6253 | try writer.print("{}\n", .{self.got.fmt(self)}); | ||
| 6254 | try writer.print("{}\n", .{self.zig_got.fmt(self)}); | 6268 | try writer.print("{}\n", .{self.zig_got.fmt(self)}); |
| 6269 | try writer.print("{}\n", .{self.got.fmt(self)}); | ||
| 6270 | try writer.print("{}\n", .{self.plt.fmt(self)}); | ||
| 6255 | 6271 | ||
| 6256 | try writer.writeAll("Output COMDAT groups\n"); | 6272 | try writer.writeAll("Output COMDAT groups\n"); |
| 6257 | for (self.comdat_group_sections.items) |cg| { | 6273 | for (self.comdat_group_sections.items) |cg| { |
src/link/Elf/Symbol.zig+5| ... | @@ -399,6 +399,11 @@ pub const Flags = packed struct { | ... | @@ -399,6 +399,11 @@ pub const Flags = packed struct { |
| 399 | /// Whether the symbol contains .zig.got indirection. | 399 | /// Whether the symbol contains .zig.got indirection. |
| 400 | needs_zig_got: bool = false, | 400 | needs_zig_got: bool = false, |
| 401 | has_zig_got: bool = false, | 401 | has_zig_got: bool = false, |
| 402 | |||
| 403 | /// Whether the symbol is a TLS variable. | ||
| 404 | /// TODO this is really not needed if only we operated on esyms between | ||
| 405 | /// codegen and ZigObject. | ||
| 406 | is_tls: bool = false, | ||
| 402 | }; | 407 | }; |
| 403 | 408 | ||
| 404 | pub const Extra = struct { | 409 | pub const Extra = struct { |
src/link/Elf/ZigObject.zig+150-77| ... | @@ -29,6 +29,9 @@ lazy_syms: LazySymbolTable = .{}, | ... | @@ -29,6 +29,9 @@ lazy_syms: LazySymbolTable = .{}, |
| 29 | /// Table of tracked Decls. | 29 | /// Table of tracked Decls. |
| 30 | decls: DeclTable = .{}, | 30 | decls: DeclTable = .{}, |
| 31 | 31 | ||
| 32 | /// TLS variables indexed by Atom.Index. | ||
| 33 | tls_variables: TlsTable = .{}, | ||
| 34 | |||
| 32 | /// Table of unnamed constants associated with a parent `Decl`. | 35 | /// Table of unnamed constants associated with a parent `Decl`. |
| 33 | /// We store them here so that we can free the constants whenever the `Decl` | 36 | /// We store them here so that we can free the constants whenever the `Decl` |
| 34 | /// needs updating or is freed. | 37 | /// needs updating or is freed. |
| ... | @@ -137,6 +140,11 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { | ... | @@ -137,6 +140,11 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { |
| 137 | self.anon_decls.deinit(allocator); | 140 | self.anon_decls.deinit(allocator); |
| 138 | } | 141 | } |
| 139 | 142 | ||
| 143 | for (self.tls_variables.values()) |*tlv| { | ||
| 144 | tlv.deinit(allocator); | ||
| 145 | } | ||
| 146 | self.tls_variables.deinit(allocator); | ||
| 147 | |||
| 140 | if (self.dwarf) |*dw| { | 148 | if (self.dwarf) |*dw| { |
| 141 | dw.deinit(); | 149 | dw.deinit(); |
| 142 | } | 150 | } |
| ... | @@ -212,8 +220,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void { | ... | @@ -212,8 +220,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void { |
| 212 | self.saveDebugSectionsSizes(elf_file); | 220 | self.saveDebugSectionsSizes(elf_file); |
| 213 | } | 221 | } |
| 214 | 222 | ||
| 215 | try self.sortSymbols(elf_file); | ||
| 216 | |||
| 217 | // The point of flushModule() is to commit changes, so in theory, nothing should | 223 | // The point of flushModule() is to commit changes, so in theory, nothing should |
| 218 | // be dirty after this. However, it is possible for some things to remain | 224 | // be dirty after this. However, it is possible for some things to remain |
| 219 | // dirty because they fail to be written in the event of compile errors, | 225 | // dirty because they fail to be written in the event of compile errors, |
| ... | @@ -280,6 +286,7 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index { | ... | @@ -280,6 +286,7 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index { |
| 280 | self.local_esyms.items(.elf_sym)[esym_index].st_shndx = SHN_ATOM; | 286 | self.local_esyms.items(.elf_sym)[esym_index].st_shndx = SHN_ATOM; |
| 281 | symbol_ptr.esym_index = esym_index; | 287 | symbol_ptr.esym_index = esym_index; |
| 282 | 288 | ||
| 289 | // TODO I'm thinking that maybe we shouldn' set this value unless it's actually needed? | ||
| 283 | const relocs_index = @as(u32, @intCast(self.relocs.items.len)); | 290 | const relocs_index = @as(u32, @intCast(self.relocs.items.len)); |
| 284 | const relocs = try self.relocs.addOne(gpa); | 291 | const relocs = try self.relocs.addOne(gpa); |
| 285 | relocs.* = .{}; | 292 | relocs.* = .{}; |
| ... | @@ -388,6 +395,19 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void { | ... | @@ -388,6 +395,19 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void { |
| 388 | } | 395 | } |
| 389 | } | 396 | } |
| 390 | 397 | ||
| 398 | pub fn allocateTlvAtoms(self: ZigObject, elf_file: *Elf) void { | ||
| 399 | for (self.tls_variables.keys(), self.tls_variables.values()) |atom_index, tlv| { | ||
| 400 | const atom = elf_file.atom(atom_index) orelse continue; | ||
| 401 | if (!atom.flags.alive) continue; | ||
| 402 | const local = elf_file.symbol(tlv.symbol_index); | ||
| 403 | const shdr = elf_file.shdrs.items[atom.output_section_index]; | ||
| 404 | atom.value += shdr.sh_addr; | ||
| 405 | local.value = atom.value; | ||
| 406 | |||
| 407 | // TODO exported TLS vars | ||
| 408 | } | ||
| 409 | } | ||
| 410 | |||
| 391 | pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void { | 411 | pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void { |
| 392 | for (self.atoms.items) |atom_index| { | 412 | for (self.atoms.items) |atom_index| { |
| 393 | const atom = elf_file.atom(atom_index) orelse continue; | 413 | const atom = elf_file.atom(atom_index) orelse continue; |
| ... | @@ -421,72 +441,6 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void { | ... | @@ -421,72 +441,6 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void { |
| 421 | } | 441 | } |
| 422 | } | 442 | } |
| 423 | 443 | ||
| 424 | fn sortSymbols(self: *ZigObject, elf_file: *Elf) error{OutOfMemory}!void { | ||
| 425 | _ = self; | ||
| 426 | _ = elf_file; | ||
| 427 | // const Entry = struct { | ||
| 428 | // index: Symbol.Index, | ||
| 429 | |||
| 430 | // const Ctx = struct { | ||
| 431 | // zobj: ZigObject, | ||
| 432 | // efile: *Elf, | ||
| 433 | // }; | ||
| 434 | |||
| 435 | // pub fn lessThan(ctx: Ctx, lhs: @This(), rhs: @This()) bool { | ||
| 436 | // const lhs_sym = ctx.efile.symbol(zobj.symbol(lhs.index)); | ||
| 437 | // const rhs_sym = ctx.efile.symbol(zobj.symbol(rhs.index)); | ||
| 438 | // if (lhs_sym.outputShndx() != null and rhs_sym.outputShndx() != null) { | ||
| 439 | // if (lhs_sym.output_section_index == rhs_sym.output_section_index) { | ||
| 440 | // if (lhs_sym.value == rhs_sym.value) { | ||
| 441 | // return lhs_sym.name_offset < rhs_sym.name_offset; | ||
| 442 | // } | ||
| 443 | // return lhs_sym.value < rhs_sym.value; | ||
| 444 | // } | ||
| 445 | // return lhs_sym.output_section_index < rhs_sym.output_section_index; | ||
| 446 | // } | ||
| 447 | // if (lhs_sym.outputShndx() != null) { | ||
| 448 | // if (rhs_sym.isAbs(ctx.efile)) return false; | ||
| 449 | // return true; | ||
| 450 | // } | ||
| 451 | // return false; | ||
| 452 | // } | ||
| 453 | // }; | ||
| 454 | |||
| 455 | // const gpa = elf_file.base.allocator; | ||
| 456 | |||
| 457 | // { | ||
| 458 | // const sorted = try gpa.alloc(Entry, self.local_symbols.items.len); | ||
| 459 | // defer gpa.free(sorted); | ||
| 460 | // for (0..self.local_symbols.items.len) |index| { | ||
| 461 | // sorted[i] = .{ .index = @as(Symbol.Index, @intCast(index)) }; | ||
| 462 | // } | ||
| 463 | // mem.sort(Entry, sorted, .{ .zobj = self, .efile = elf_file }, Entry.lessThan); | ||
| 464 | |||
| 465 | // const backlinks = try gpa.alloc(Symbol.Index, sorted.len); | ||
| 466 | // defer gpa.free(backlinks); | ||
| 467 | // for (sorted, 0..) |entry, i| { | ||
| 468 | // backlinks[entry.index] = @as(Symbol.Index, @intCast(i)); | ||
| 469 | // } | ||
| 470 | |||
| 471 | // const local_symbols = try self.local_symbols.toOwnedSlice(gpa); | ||
| 472 | // defer gpa.free(local_symbols); | ||
| 473 | |||
| 474 | // try self.local_symbols.ensureTotalCapacityPrecise(gpa, local_symbols.len); | ||
| 475 | // for (sorted) |entry| { | ||
| 476 | // self.local_symbols.appendAssumeCapacity(local_symbols[entry.index]); | ||
| 477 | // } | ||
| 478 | |||
| 479 | // for (self.) | ||
| 480 | // } | ||
| 481 | |||
| 482 | // const sorted_globals = try gpa.alloc(Entry, self.global_symbols.items.len); | ||
| 483 | // defer gpa.free(sorted_globals); | ||
| 484 | // for (self.global_symbols.items, 0..) |index, i| { | ||
| 485 | // sorted_globals[i] = .{ .index = index }; | ||
| 486 | // } | ||
| 487 | // mem.sort(Entry, sorted_globals, elf_file, Entry.lessThan); | ||
| 488 | } | ||
| 489 | |||
| 490 | pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) error{OutOfMemory}!void { | 444 | pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) error{OutOfMemory}!void { |
| 491 | const gpa = elf_file.base.allocator; | 445 | const gpa = elf_file.base.allocator; |
| 492 | 446 | ||
| ... | @@ -537,7 +491,9 @@ pub fn addAtomsToRelaSections(self: ZigObject, elf_file: *Elf) !void { | ... | @@ -537,7 +491,9 @@ pub fn addAtomsToRelaSections(self: ZigObject, elf_file: *Elf) !void { |
| 537 | for (self.atoms.items) |atom_index| { | 491 | for (self.atoms.items) |atom_index| { |
| 538 | const atom = elf_file.atom(atom_index) orelse continue; | 492 | const atom = elf_file.atom(atom_index) orelse continue; |
| 539 | if (!atom.flags.alive) continue; | 493 | if (!atom.flags.alive) continue; |
| 540 | _ = atom.relocsShndx() orelse continue; | 494 | const rela_shndx = atom.relocsShndx() orelse continue; |
| 495 | // TODO this check will become obsolete when we rework our relocs mechanism at the ZigObject level | ||
| 496 | if (self.relocs.items[rela_shndx].items.len == 0) continue; | ||
| 541 | const out_shndx = atom.outputShndx().?; | 497 | const out_shndx = atom.outputShndx().?; |
| 542 | const out_shdr = elf_file.shdrs.items[out_shndx]; | 498 | const out_shdr = elf_file.shdrs.items[out_shndx]; |
| 543 | if (out_shdr.sh_type == elf.SHT_NOBITS) continue; | 499 | if (out_shdr.sh_type == elf.SHT_NOBITS) continue; |
| ... | @@ -583,6 +539,13 @@ pub fn codeAlloc(self: ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 | ... | @@ -583,6 +539,13 @@ pub fn codeAlloc(self: ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 |
| 583 | const atom = elf_file.atom(atom_index).?; | 539 | const atom = elf_file.atom(atom_index).?; |
| 584 | assert(atom.file_index == self.index); | 540 | assert(atom.file_index == self.index); |
| 585 | const shdr = &elf_file.shdrs.items[atom.outputShndx().?]; | 541 | const shdr = &elf_file.shdrs.items[atom.outputShndx().?]; |
| 542 | |||
| 543 | if (shdr.sh_flags & elf.SHF_TLS != 0) { | ||
| 544 | const tlv = self.tls_variables.get(atom_index).?; | ||
| 545 | const code = try gpa.dupe(u8, tlv.code); | ||
| 546 | return code; | ||
| 547 | } | ||
| 548 | |||
| 586 | const file_offset = shdr.sh_offset + atom.value - shdr.sh_addr; | 549 | const file_offset = shdr.sh_offset + atom.value - shdr.sh_addr; |
| 587 | const size = std.math.cast(usize, atom.size) orelse return error.Overflow; | 550 | const size = std.math.cast(usize, atom.size) orelse return error.Overflow; |
| 588 | const code = try gpa.alloc(u8, size); | 551 | const code = try gpa.alloc(u8, size); |
| ... | @@ -705,7 +668,12 @@ pub fn getOrCreateMetadataForLazySymbol( | ... | @@ -705,7 +668,12 @@ pub fn getOrCreateMetadataForLazySymbol( |
| 705 | }, | 668 | }, |
| 706 | }; | 669 | }; |
| 707 | switch (metadata.state.*) { | 670 | switch (metadata.state.*) { |
| 708 | .unused => metadata.symbol_index.* = try self.addAtom(elf_file), | 671 | .unused => { |
| 672 | const symbol_index = try self.addAtom(elf_file); | ||
| 673 | const sym = elf_file.symbol(symbol_index); | ||
| 674 | sym.flags.needs_zig_got = true; | ||
| 675 | metadata.symbol_index.* = symbol_index; | ||
| 676 | }, | ||
| 709 | .pending_flush => return metadata.symbol_index.*, | 677 | .pending_flush => return metadata.symbol_index.*, |
| 710 | .flushed => {}, | 678 | .flushed => {}, |
| 711 | } | 679 | } |
| ... | @@ -760,20 +728,55 @@ pub fn getOrCreateMetadataForDecl( | ... | @@ -760,20 +728,55 @@ pub fn getOrCreateMetadataForDecl( |
| 760 | ) !Symbol.Index { | 728 | ) !Symbol.Index { |
| 761 | const gop = try self.decls.getOrPut(elf_file.base.allocator, decl_index); | 729 | const gop = try self.decls.getOrPut(elf_file.base.allocator, decl_index); |
| 762 | if (!gop.found_existing) { | 730 | if (!gop.found_existing) { |
| 763 | gop.value_ptr.* = .{ .symbol_index = try self.addAtom(elf_file) }; | 731 | const single_threaded = elf_file.base.options.single_threaded; |
| 732 | const symbol_index = try self.addAtom(elf_file); | ||
| 733 | const mod = elf_file.base.options.module.?; | ||
| 734 | const decl = mod.declPtr(decl_index); | ||
| 735 | const sym = elf_file.symbol(symbol_index); | ||
| 736 | if (decl.getOwnedVariable(mod)) |variable| { | ||
| 737 | if (variable.is_threadlocal and !single_threaded) { | ||
| 738 | sym.flags.is_tls = true; | ||
| 739 | } | ||
| 740 | } | ||
| 741 | if (!sym.flags.is_tls) { | ||
| 742 | sym.flags.needs_zig_got = true; | ||
| 743 | } | ||
| 744 | gop.value_ptr.* = .{ .symbol_index = symbol_index }; | ||
| 764 | } | 745 | } |
| 765 | return gop.value_ptr.symbol_index; | 746 | return gop.value_ptr.symbol_index; |
| 766 | } | 747 | } |
| 767 | 748 | ||
| 768 | fn getDeclShdrIndex(self: *ZigObject, elf_file: *Elf, decl_index: Module.Decl.Index, code: []const u8) u16 { | 749 | fn getDeclShdrIndex( |
| 750 | self: *ZigObject, | ||
| 751 | elf_file: *Elf, | ||
| 752 | decl: *const Module.Decl, | ||
| 753 | code: []const u8, | ||
| 754 | ) error{OutOfMemory}!u16 { | ||
| 769 | _ = self; | 755 | _ = self; |
| 770 | const mod = elf_file.base.options.module.?; | 756 | const mod = elf_file.base.options.module.?; |
| 771 | const decl = mod.declPtr(decl_index); | 757 | const single_threaded = elf_file.base.options.single_threaded; |
| 772 | const shdr_index = switch (decl.ty.zigTypeTag(mod)) { | 758 | const shdr_index = switch (decl.ty.zigTypeTag(mod)) { |
| 773 | // TODO: what if this is a function pointer? | ||
| 774 | .Fn => elf_file.zig_text_section_index.?, | 759 | .Fn => elf_file.zig_text_section_index.?, |
| 775 | else => blk: { | 760 | else => blk: { |
| 776 | if (decl.getOwnedVariable(mod)) |variable| { | 761 | if (decl.getOwnedVariable(mod)) |variable| { |
| 762 | if (variable.is_threadlocal and !single_threaded) { | ||
| 763 | const is_all_zeroes = for (code) |byte| { | ||
| 764 | if (byte != 0) break false; | ||
| 765 | } else true; | ||
| 766 | if (is_all_zeroes) break :blk elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{ | ||
| 767 | .type = elf.SHT_NOBITS, | ||
| 768 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS, | ||
| 769 | .name = ".tbss", | ||
| 770 | .offset = std.math.maxInt(u64), | ||
| 771 | }); | ||
| 772 | |||
| 773 | break :blk elf_file.sectionByName(".tdata") orelse try elf_file.addSection(.{ | ||
| 774 | .type = elf.SHT_PROGBITS, | ||
| 775 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS, | ||
| 776 | .name = ".tdata", | ||
| 777 | .offset = std.math.maxInt(u64), | ||
| 778 | }); | ||
| 779 | } | ||
| 777 | if (variable.is_const) break :blk elf_file.zig_data_rel_ro_section_index.?; | 780 | if (variable.is_const) break :blk elf_file.zig_data_rel_ro_section_index.?; |
| 778 | if (variable.init.toValue().isUndefDeep(mod)) { | 781 | if (variable.init.toValue().isUndefDeep(mod)) { |
| 779 | const mode = elf_file.base.options.optimize_mode; | 782 | const mode = elf_file.base.options.optimize_mode; |
| ... | @@ -799,6 +802,7 @@ fn updateDeclCode( | ... | @@ -799,6 +802,7 @@ fn updateDeclCode( |
| 799 | elf_file: *Elf, | 802 | elf_file: *Elf, |
| 800 | decl_index: Module.Decl.Index, | 803 | decl_index: Module.Decl.Index, |
| 801 | sym_index: Symbol.Index, | 804 | sym_index: Symbol.Index, |
| 805 | shdr_index: u16, | ||
| 802 | code: []const u8, | 806 | code: []const u8, |
| 803 | stt_bits: u8, | 807 | stt_bits: u8, |
| 804 | ) !void { | 808 | ) !void { |
| ... | @@ -815,7 +819,6 @@ fn updateDeclCode( | ... | @@ -815,7 +819,6 @@ fn updateDeclCode( |
| 815 | const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index]; | 819 | const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index]; |
| 816 | const atom_ptr = sym.atom(elf_file).?; | 820 | const atom_ptr = sym.atom(elf_file).?; |
| 817 | 821 | ||
| 818 | const shdr_index = self.getDeclShdrIndex(elf_file, decl_index, code); | ||
| 819 | sym.output_section_index = shdr_index; | 822 | sym.output_section_index = shdr_index; |
| 820 | atom_ptr.output_section_index = shdr_index; | 823 | atom_ptr.output_section_index = shdr_index; |
| 821 | 824 | ||
| ... | @@ -893,6 +896,58 @@ fn updateDeclCode( | ... | @@ -893,6 +896,58 @@ fn updateDeclCode( |
| 893 | } | 896 | } |
| 894 | } | 897 | } |
| 895 | 898 | ||
| 899 | fn updateTlv( | ||
| 900 | self: *ZigObject, | ||
| 901 | elf_file: *Elf, | ||
| 902 | decl_index: Module.Decl.Index, | ||
| 903 | sym_index: Symbol.Index, | ||
| 904 | shndx: u16, | ||
| 905 | code: []const u8, | ||
| 906 | ) !void { | ||
| 907 | const gpa = elf_file.base.allocator; | ||
| 908 | const mod = elf_file.base.options.module.?; | ||
| 909 | const decl = mod.declPtr(decl_index); | ||
| 910 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); | ||
| 911 | |||
| 912 | log.debug("updateTlv {s} ({*})", .{ decl_name, decl }); | ||
| 913 | |||
| 914 | const required_alignment = decl.getAlignment(mod); | ||
| 915 | |||
| 916 | const sym = elf_file.symbol(sym_index); | ||
| 917 | const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index]; | ||
| 918 | const atom_ptr = sym.atom(elf_file).?; | ||
| 919 | |||
| 920 | sym.output_section_index = shndx; | ||
| 921 | atom_ptr.output_section_index = shndx; | ||
| 922 | |||
| 923 | sym.name_offset = try self.strtab.insert(gpa, decl_name); | ||
| 924 | atom_ptr.flags.alive = true; | ||
| 925 | atom_ptr.name_offset = sym.name_offset; | ||
| 926 | esym.st_name = sym.name_offset; | ||
| 927 | esym.st_info = elf.STT_TLS; | ||
| 928 | esym.st_size = code.len; | ||
| 929 | |||
| 930 | atom_ptr.alignment = required_alignment; | ||
| 931 | atom_ptr.size = code.len; | ||
| 932 | |||
| 933 | { | ||
| 934 | const gop = try self.tls_variables.getOrPut(gpa, atom_ptr.atom_index); | ||
| 935 | assert(!gop.found_existing); // TODO incremental updates | ||
| 936 | gop.value_ptr.* = .{ .symbol_index = sym_index }; | ||
| 937 | |||
| 938 | // We only store the data for the TLV if it's non-zerofill. | ||
| 939 | if (elf_file.shdrs.items[shndx].sh_type != elf.SHT_NOBITS) { | ||
| 940 | gop.value_ptr.code = try gpa.dupe(u8, code); | ||
| 941 | } | ||
| 942 | } | ||
| 943 | |||
| 944 | { | ||
| 945 | const gop = try elf_file.output_sections.getOrPut(gpa, atom_ptr.output_section_index); | ||
| 946 | if (!gop.found_existing) gop.value_ptr.* = .{}; | ||
| 947 | try gop.value_ptr.append(gpa, atom_ptr.atom_index); | ||
| 948 | } | ||
| 949 | } | ||
| 950 | |||
| 896 | pub fn updateFunc( | 951 | pub fn updateFunc( |
| 897 | self: *ZigObject, | 952 | self: *ZigObject, |
| 898 | elf_file: *Elf, | 953 | elf_file: *Elf, |
| ... | @@ -947,7 +1002,10 @@ pub fn updateFunc( | ... | @@ -947,7 +1002,10 @@ pub fn updateFunc( |
| 947 | return; | 1002 | return; |
| 948 | }, | 1003 | }, |
| 949 | }; | 1004 | }; |
| 950 | try self.updateDeclCode(elf_file, decl_index, sym_index, code, elf.STT_FUNC); | 1005 | |
| 1006 | const shndx = try self.getDeclShdrIndex(elf_file, decl, code); | ||
| 1007 | try self.updateDeclCode(elf_file, decl_index, sym_index, shndx, code, elf.STT_FUNC); | ||
| 1008 | |||
| 951 | if (decl_state) |*ds| { | 1009 | if (decl_state) |*ds| { |
| 952 | const sym = elf_file.symbol(sym_index); | 1010 | const sym = elf_file.symbol(sym_index); |
| 953 | try self.dwarf.?.commitDeclState( | 1011 | try self.dwarf.?.commitDeclState( |
| ... | @@ -1026,7 +1084,12 @@ pub fn updateDecl( | ... | @@ -1026,7 +1084,12 @@ pub fn updateDecl( |
| 1026 | }, | 1084 | }, |
| 1027 | }; | 1085 | }; |
| 1028 | 1086 | ||
| 1029 | try self.updateDeclCode(elf_file, decl_index, sym_index, code, elf.STT_OBJECT); | 1087 | const shndx = try self.getDeclShdrIndex(elf_file, decl, code); |
| 1088 | if (elf_file.shdrs.items[shndx].sh_flags & elf.SHF_TLS != 0) | ||
| 1089 | try self.updateTlv(elf_file, decl_index, sym_index, shndx, code) | ||
| 1090 | else | ||
| 1091 | try self.updateDeclCode(elf_file, decl_index, sym_index, shndx, code, elf.STT_OBJECT); | ||
| 1092 | |||
| 1030 | if (decl_state) |*ds| { | 1093 | if (decl_state) |*ds| { |
| 1031 | const sym = elf_file.symbol(sym_index); | 1094 | const sym = elf_file.symbol(sym_index); |
| 1032 | try self.dwarf.?.commitDeclState( | 1095 | try self.dwarf.?.commitDeclState( |
| ... | @@ -1454,11 +1517,21 @@ const DeclMetadata = struct { | ... | @@ -1454,11 +1517,21 @@ const DeclMetadata = struct { |
| 1454 | } | 1517 | } |
| 1455 | }; | 1518 | }; |
| 1456 | 1519 | ||
| 1520 | const TlsVariable = struct { | ||
| 1521 | symbol_index: Symbol.Index, | ||
| 1522 | code: []const u8 = &[0]u8{}, | ||
| 1523 | |||
| 1524 | fn deinit(tlv: *TlsVariable, allocator: Allocator) void { | ||
| 1525 | allocator.free(tlv.code); | ||
| 1526 | } | ||
| 1527 | }; | ||
| 1528 | |||
| 1457 | const AtomList = std.ArrayListUnmanaged(Atom.Index); | 1529 | const AtomList = std.ArrayListUnmanaged(Atom.Index); |
| 1458 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index)); | 1530 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index)); |
| 1459 | const DeclTable = std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata); | 1531 | const DeclTable = std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata); |
| 1460 | const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata); | 1532 | const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata); |
| 1461 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); | 1533 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); |
| 1534 | const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlsVariable); | ||
| 1462 | 1535 | ||
| 1463 | const assert = std.debug.assert; | 1536 | const assert = std.debug.assert; |
| 1464 | const builtin = @import("builtin"); | 1537 | const builtin = @import("builtin"); |
src/link/Elf/synthetic_sections.zig+30| ... | @@ -935,6 +935,36 @@ pub const PltSection = struct { | ... | @@ -935,6 +935,36 @@ pub const PltSection = struct { |
| 935 | ilocal += 1; | 935 | ilocal += 1; |
| 936 | } | 936 | } |
| 937 | } | 937 | } |
| 938 | |||
| 939 | const FormatCtx = struct { | ||
| 940 | plt: PltSection, | ||
| 941 | elf_file: *Elf, | ||
| 942 | }; | ||
| 943 | |||
| 944 | pub fn fmt(plt: PltSection, elf_file: *Elf) std.fmt.Formatter(format2) { | ||
| 945 | return .{ .data = .{ .plt = plt, .elf_file = elf_file } }; | ||
| 946 | } | ||
| 947 | |||
| 948 | pub fn format2( | ||
| 949 | ctx: FormatCtx, | ||
| 950 | comptime unused_fmt_string: []const u8, | ||
| 951 | options: std.fmt.FormatOptions, | ||
| 952 | writer: anytype, | ||
| 953 | ) !void { | ||
| 954 | _ = options; | ||
| 955 | _ = unused_fmt_string; | ||
| 956 | try writer.writeAll("PLT\n"); | ||
| 957 | for (ctx.plt.symbols.items, 0..) |symbol_index, i| { | ||
| 958 | const symbol = ctx.elf_file.symbol(symbol_index); | ||
| 959 | try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ | ||
| 960 | i, | ||
| 961 | symbol.pltAddress(ctx.elf_file), | ||
| 962 | symbol_index, | ||
| 963 | symbol.address(.{}, ctx.elf_file), | ||
| 964 | symbol.name(ctx.elf_file), | ||
| 965 | }); | ||
| 966 | } | ||
| 967 | } | ||
| 938 | }; | 968 | }; |
| 939 | 969 | ||
| 940 | pub const GotPltSection = struct { | 970 | pub const GotPltSection = struct { |
src/target.zig+1-1| ... | @@ -654,7 +654,7 @@ pub fn supportsTailCall(target: std.Target, backend: std.builtin.CompilerBackend | ... | @@ -654,7 +654,7 @@ pub fn supportsTailCall(target: std.Target, backend: std.builtin.CompilerBackend |
| 654 | 654 | ||
| 655 | pub fn supportsThreads(target: std.Target, backend: std.builtin.CompilerBackend) bool { | 655 | pub fn supportsThreads(target: std.Target, backend: std.builtin.CompilerBackend) bool { |
| 656 | return switch (backend) { | 656 | return switch (backend) { |
| 657 | .stage2_x86_64 => target.ofmt == .macho, | 657 | .stage2_x86_64 => target.ofmt == .macho or target.ofmt == .elf, |
| 658 | else => true, | 658 | else => true, |
| 659 | }; | 659 | }; |
| 660 | } | 660 | } |