| ... | @@ -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, |
| ... | @@ -353,24 +357,56 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) | ... | @@ -353,24 +357,56 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 353 | assert(mem_op.sib.scale_index.scale == 0); | 357 | assert(mem_op.sib.scale_index.scale == 0); |
| 354 | | 358 | |
| 355 | if (isTls(sym, lower.bin_file)) { | 359 | if (isTls(sym, lower.bin_file)) { |
| 356 | lower.result_insts[lower.result_insts_len] = | 360 | // TODO handle extern TLS vars, i.e., emit GD model |
| 357 | try Instruction.new(.none, .mov, &[_]Operand{ | 361 | if (lower.bin_file.options.pic) { |
| 358 | .{ .reg = ops[0].reg.to64() }, | 362 | // Here, we currently assume local dynamic TLS vars, and so |
| 359 | .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .fs } }) }, | 363 | // we emit LD model. |
| 360 | }); | 364 | _ = lower.reloc(.{ .linker_tlsld = sym }); |
| 361 | lower.result_insts_len += 1; | 365 | lower.result_insts[lower.result_insts_len] = |
| 362 | _ = lower.reloc(.{ .linker_reloc = sym }); | 366 | try Instruction.new(.none, .lea, &[_]Operand{ |
| 363 | if (lower.bin_file.cast(link.File.Elf)) |elf_file| { | 367 | .{ .reg = ops[0].reg.to64() }, |
| 364 | const sym_index = elf_file.zigObjectPtr().?.symbol(sym.sym_index); | 368 | .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }, |
| 365 | elf_file.symbol(sym_index).flags.needs_zig_got = false; | 369 | }); |
| 366 | } | 370 | lower.result_insts_len += 1; |
| 367 | emit_mnemonic = .lea; | 371 | if (lower.bin_file.cast(link.File.Elf)) |elf_file| { |
| 368 | switch (mnemonic) { | 372 | _ = lower.reloc(.{ .linker_extern_fn = .{ |
| 369 | .lea, .mov => break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ | 373 | .atom_index = sym.atom_index, |
| | 374 | .sym_index = try elf_file.getGlobalSymbol("__tls_get_address", 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 | if (lower.bin_file.cast(link.File.Elf)) |elf_file| { |
| | 384 | const sym_index = elf_file.zigObjectPtr().?.symbol(sym.sym_index); |
| | 385 | elf_file.symbol(sym_index).flags.needs_zig_got = false; |
| | 386 | } |
| | 387 | emit_mnemonic = .lea; |
| | 388 | break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ |
| 370 | .base = .{ .reg = ops[0].reg.to64() }, | 389 | .base = .{ .reg = ops[0].reg.to64() }, |
| 371 | .disp = undefined, | 390 | .disp = undefined, |
| 372 | }) }, | 391 | }) }; |
| 373 | else => unreachable, | 392 | } else { |
| | 393 | // Since we are linking statically, we emit LE model directly. |
| | 394 | lower.result_insts[lower.result_insts_len] = |
| | 395 | try Instruction.new(.none, .mov, &[_]Operand{ |
| | 396 | .{ .reg = ops[0].reg.to64() }, |
| | 397 | .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .fs } }) }, |
| | 398 | }); |
| | 399 | lower.result_insts_len += 1; |
| | 400 | _ = lower.reloc(.{ .linker_reloc = sym }); |
| | 401 | if (lower.bin_file.cast(link.File.Elf)) |elf_file| { |
| | 402 | const sym_index = elf_file.zigObjectPtr().?.symbol(sym.sym_index); |
| | 403 | elf_file.symbol(sym_index).flags.needs_zig_got = false; |
| | 404 | } |
| | 405 | emit_mnemonic = .lea; |
| | 406 | break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ |
| | 407 | .base = .{ .reg = ops[0].reg.to64() }, |
| | 408 | .disp = undefined, |
| | 409 | }) }; |
| 374 | } | 410 | } |
| 375 | } | 411 | } |
| 376 | | 412 | |