diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -126,6 +126,7 @@ // Call reportUndefinedSymbols() after calling scanRelocations() to emit // the diagnostics. template void scanRelocations(InputSectionBase &); +void postScanRelocations(); template void reportUndefinedSymbols(); diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -1419,116 +1419,23 @@ return; } - // Non-preemptible ifuncs require special handling. First, handle the usual - // case where the symbol isn't one of these. - if (!sym.isGnuIFunc() || sym.isPreemptible) { - // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol. - if (needsPlt(expr) && !sym.isInPlt()) - addPltEntry(in.plt, in.gotPlt, in.relaPlt, target->pltRel, sym); - - // Create a GOT slot if a relocation needs GOT. - if (needsGot(expr)) { - if (config->emachine == EM_MIPS) { - // MIPS ABI has special rules to process GOT entries and doesn't - // require relocation entries for them. A special case is TLS - // relocations. In that case dynamic loader applies dynamic - // relocations to initialize TLS GOT entries. - // See "Global Offset Table" in Chapter 5 in the following document - // for detailed description: - // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - in.mipsGot->addEntry(*sec.file, sym, addend, expr); - } else if (!sym.isInGot()) { - addGotEntry(sym); - } + if (needsGot(expr)) { + if (config->emachine == EM_MIPS) { + // MIPS ABI has special rules to process GOT entries and doesn't + // require relocation entries for them. A special case is TLS + // relocations. In that case dynamic loader applies dynamic + // relocations to initialize TLS GOT entries. + // See "Global Offset Table" in Chapter 5 in the following document + // for detailed description: + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + in.mipsGot->addEntry(*sec.file, sym, addend, expr); + } else { + sym.needsGot = true; } + } else if (needsPlt(expr)) { + sym.needsPlt = true; } else { - // Handle a reference to a non-preemptible ifunc. These are special in a - // few ways: - // - // - Unlike most non-preemptible symbols, non-preemptible ifuncs do not have - // a fixed value. But assuming that all references to the ifunc are - // GOT-generating or PLT-generating, the handling of an ifunc is - // relatively straightforward. We create a PLT entry in Iplt, which is - // usually at the end of .plt, which makes an indirect call using a - // matching GOT entry in igotPlt, which is usually at the end of .got.plt. - // The GOT entry is relocated using an IRELATIVE relocation in relaIplt, - // which is usually at the end of .rela.plt. Unlike most relocations in - // .rela.plt, which may be evaluated lazily without -z now, dynamic - // loaders evaluate IRELATIVE relocs eagerly, which means that for - // IRELATIVE relocs only, GOT-generating relocations can point directly to - // .got.plt without requiring a separate GOT entry. - // - // - Despite the fact that an ifunc does not have a fixed value, compilers - // that are not passed -fPIC will assume that they do, and will emit - // direct (non-GOT-generating, non-PLT-generating) relocations to the - // symbol. This means that if a direct relocation to the symbol is - // seen, the linker must set a value for the symbol, and this value must - // be consistent no matter what type of reference is made to the symbol. - // This can be done by creating a PLT entry for the symbol in the way - // described above and making it canonical, that is, making all references - // point to the PLT entry instead of the resolver. In lld we also store - // the address of the PLT entry in the dynamic symbol table, which means - // that the symbol will also have the same value in other modules. - // Because the value loaded from the GOT needs to be consistent with - // the value computed using a direct relocation, a non-preemptible ifunc - // may end up with two GOT entries, one in .got.plt that points to the - // address returned by the resolver and is used only by the PLT entry, - // and another in .got that points to the PLT entry and is used by - // GOT-generating relocations. - // - // - The fact that these symbols do not have a fixed value makes them an - // exception to the general rule that a statically linked executable does - // not require any form of dynamic relocation. To handle these relocations - // correctly, the IRELATIVE relocations are stored in an array which a - // statically linked executable's startup code must enumerate using the - // linker-defined symbols __rela?_iplt_{start,end}. - if (!sym.isInPlt()) { - // Create PLT and GOTPLT slots for the symbol. - sym.isInIplt = true; - - // Create a copy of the symbol to use as the target of the IRELATIVE - // relocation in the igotPlt. This is in case we make the PLT canonical - // later, which would overwrite the original symbol. - // - // FIXME: Creating a copy of the symbol here is a bit of a hack. All - // that's really needed to create the IRELATIVE is the section and value, - // so ideally we should just need to copy those. - auto *directSym = make(cast(sym)); - addPltEntry(in.iplt, in.igotPlt, in.relaIplt, target->iRelativeRel, - *directSym); - sym.pltIndex = directSym->pltIndex; - } - if (needsGot(expr)) { - // Redirect GOT accesses to point to the Igot. - // - // This field is also used to keep track of whether we ever needed a GOT - // entry. If we did and we make the PLT canonical later, we'll need to - // create a GOT entry pointing to the PLT entry for Sym. - sym.gotInIgot = true; - } else if (!needsPlt(expr)) { - // Make the ifunc's PLT entry canonical by changing the value of its - // symbol to redirect all references to point to it. - auto &d = cast(sym); - d.section = in.iplt; - d.value = sym.pltIndex * target->ipltEntrySize; - d.size = 0; - // It's important to set the symbol type here so that dynamic loaders - // don't try to call the PLT as if it were an ifunc resolver. - d.type = STT_FUNC; - - if (sym.gotInIgot) { - // We previously encountered a GOT generating reference that we - // redirected to the Igot. Now that the PLT entry is canonical we must - // clear the redirection to the Igot and add a GOT entry. As we've - // changed the symbol type to STT_FUNC future GOT generating references - // will naturally use this GOT entry. - // - // We don't need to worry about creating a MIPS GOT here because ifuncs - // aren't a thing on MIPS. - sym.gotInIgot = false; - addGotEntry(sym); - } - } + sym.needsNonGotPlt = true; } processRelocAux(sec, expr, type, offset, sym, addend); @@ -1609,6 +1516,98 @@ scanRelocs(s, rels.relas); } +void elf::postScanRelocations() { + auto fn = [](Symbol &sym) { + // Handle a reference to a non-preemptible ifunc. These are special in a + // few ways: + // + // - Unlike most non-preemptible symbols, non-preemptible ifuncs do not have + // a fixed value. But assuming that all references to the ifunc are + // GOT-generating or PLT-generating, the handling of an ifunc is + // relatively straightforward. We create a PLT entry in Iplt, which is + // usually at the end of .plt, which makes an indirect call using a + // matching GOT entry in igotPlt, which is usually at the end of .got.plt. + // The GOT entry is relocated using an IRELATIVE relocation in relaIplt, + // which is usually at the end of .rela.plt. Unlike most relocations in + // .rela.plt, which may be evaluated lazily without -z now, dynamic + // loaders evaluate IRELATIVE relocs eagerly, which means that for + // IRELATIVE relocs only, GOT-generating relocations can point directly to + // .got.plt without requiring a separate GOT entry. + // + // - Despite the fact that an ifunc does not have a fixed value, compilers + // that are not passed -fPIC will assume that they do, and will emit + // direct (non-GOT-generating, non-PLT-generating) relocations to the + // symbol. This means that if a direct relocation to the symbol is + // seen, the linker must set a value for the symbol, and this value must + // be consistent no matter what type of reference is made to the symbol. + // This can be done by creating a PLT entry for the symbol in the way + // described above and making it canonical, that is, making all references + // point to the PLT entry instead of the resolver. In lld we also store + // the address of the PLT entry in the dynamic symbol table, which means + // that the symbol will also have the same value in other modules. + // Because the value loaded from the GOT needs to be consistent with + // the value computed using a direct relocation, a non-preemptible ifunc + // may end up with two GOT entries, one in .got.plt that points to the + // address returned by the resolver and is used only by the PLT entry, + // and another in .got that points to the PLT entry and is used by + // GOT-generating relocations. + // + // - The fact that these symbols do not have a fixed value makes them an + // exception to the general rule that a statically linked executable does + // not require any form of dynamic relocation. To handle these relocations + // correctly, the IRELATIVE relocations are stored in an array which a + // statically linked executable's startup code must enumerate using the + // linker-defined symbols __rela?_iplt_{start,end}. + if (sym.isGnuIFunc() && !sym.isPreemptible && !config->zIfuncNoplt) { + sym.isInIplt = true; + + // Create a copy of the symbol to use as the target of the IRELATIVE + // relocation in the igotPlt. This is in case we make the PLT canonical + // later, which would overwrite the original symbol. + // + // Creating a copy of the symbol here is a bit of a hack. All that's + // really needed to create the IRELATIVE is the section and value, so + // ideally we should just need to copy those. + auto *directSym = make(cast(sym)); + addPltEntry(in.iplt, in.igotPlt, in.relaIplt, target->iRelativeRel, + *directSym); + sym.pltIndex = directSym->pltIndex; + + // Make the ifunc's PLT entry canonical by changing the value of its + // symbol to redirect all references to point to it. + if (sym.needsNonGotPlt) { + auto &d = cast(sym); + d.section = in.iplt; + d.value = sym.pltIndex * target->ipltEntrySize; + d.size = 0; + // It's important to set the symbol type here so that dynamic loaders + // don't try to call the PLT as if it were an ifunc resolver. + d.type = STT_FUNC; + + if (sym.needsGot) + addGotEntry(sym); + } else if (sym.needsGot) { + // Redirect GOT accesses to point to the Igot. + sym.gotInIgot = true; + } + return; + } + + if (sym.needsGot) + addGotEntry(sym); + if (sym.needsPlt && !sym.isInPlt()) + addPltEntry(in.plt, in.gotPlt, in.relaPlt, target->pltRel, sym); + }; + for (Symbol *sym : symtab->symbols()) + fn(*sym); + + // Local symbols may need the aforementioned non-preemptible ifunc handling. + // They don't need regular PLT/GOT. + for (InputFile *file : objectFiles) + for (Symbol *sym : cast(file)->getLocalSymbols()) + fn(*sym); +} + static bool mergeCmp(const InputSection *a, const InputSection *b) { // std::merge requires a strict weak ordering. if (a->outSecOff < b->outSecOff) diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -247,8 +247,8 @@ exportDynamic(isExportDynamic(k, visibility)), inDynamicList(false), canInline(false), referenced(false), traced(false), needsPltAddr(false), isInIplt(false), gotInIgot(false), isPreemptible(false), - used(!config->gcSections), needsTocRestore(false), - scriptDefined(false) {} + used(!config->gcSections), needsTocRestore(false), scriptDefined(false), + needsGot(false), needsPlt(false), needsNonGotPlt(false) {} public: // True the symbol should point to its PLT entry. @@ -279,6 +279,10 @@ // True if this symbol is defined by a linker script. uint8_t scriptDefined : 1; + uint8_t needsGot : 1; + uint8_t needsPlt : 1; + uint8_t needsNonGotPlt : 1; + // The partition whose dynamic symbol table contains this symbol's definition. uint8_t partition = 1; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1947,6 +1947,7 @@ if (!config->relocatable) { forEachRelSec(scanRelocations); reportUndefinedSymbols(); + postScanRelocations(); } } diff --git a/lld/test/ELF/arm-gnu-ifunc.s b/lld/test/ELF/arm-gnu-ifunc.s --- a/lld/test/ELF/arm-gnu-ifunc.s +++ b/lld/test/ELF/arm-gnu-ifunc.s @@ -118,8 +118,8 @@ // DISASM: : // DISASM-NEXT: 20108: bx lr // DISASM: <_start>: -// DISASM-NEXT: 2010c: bl 0x20130 -// DISASM-NEXT: 20110: bl 0x20140 +// DISASM-NEXT: 2010c: bl 0x20140 +// DISASM-NEXT: 20110: bl 0x20130 // 1 * 65536 + 244 = 0x100f4 __rel_iplt_start // DISASM-NEXT: 20114: movw r0, #244 // DISASM-NEXT: 20118: movt r0, #1 diff --git a/lld/test/ELF/bsymbolic.s b/lld/test/ELF/bsymbolic.s --- a/lld/test/ELF/bsymbolic.s +++ b/lld/test/ELF/bsymbolic.s @@ -41,9 +41,9 @@ # REL_DEF-NEXT: } # REL_DEF-NEXT: .rela.plt { # REL_DEF-NEXT: R_X86_64_JUMP_SLOT default +# REL_DEF-NEXT: R_X86_64_JUMP_SLOT notype_default # REL_DEF-NEXT: R_X86_64_JUMP_SLOT weak_default # REL_DEF-NEXT: R_X86_64_JUMP_SLOT ext_default -# REL_DEF-NEXT: R_X86_64_JUMP_SLOT notype_default # REL_DEF-NEXT: R_X86_64_JUMP_SLOT undef # REL_DEF-NEXT: } @@ -62,8 +62,8 @@ # REL_GFUN-NEXT: R_X86_64_64 data_default # REL_GFUN-NEXT: } # REL_GFUN-NEXT: .rela.plt { -# REL_GFUN-NEXT: R_X86_64_JUMP_SLOT weak_default # REL_GFUN-NEXT: R_X86_64_JUMP_SLOT notype_default +# REL_GFUN-NEXT: R_X86_64_JUMP_SLOT weak_default # REL_GFUN-NEXT: R_X86_64_JUMP_SLOT undef # REL_GFUN-NEXT: } diff --git a/lld/test/ELF/dynamic-reloc-weak.s b/lld/test/ELF/dynamic-reloc-weak.s --- a/lld/test/ELF/dynamic-reloc-weak.s +++ b/lld/test/ELF/dynamic-reloc-weak.s @@ -31,7 +31,7 @@ // CHECK-NEXT: 0x{{.*}} R_X86_64_GLOB_DAT sym1 0x0 // CHECK-NEXT: } // CHECK-NEXT: Section ({{.*}}) .rela.plt { -// CHECK-NEXT: 0x{{.*}} R_X86_64_JUMP_SLOT sym2 0x0 // CHECK-NEXT: 0x{{.*}} R_X86_64_JUMP_SLOT sym3 0x0 +// CHECK-NEXT: 0x{{.*}} R_X86_64_JUMP_SLOT sym2 0x0 // CHECK-NEXT: } // CHECK-NEXT: ] diff --git a/lld/test/ELF/gnu-ifunc-i386.s b/lld/test/ELF/gnu-ifunc-i386.s --- a/lld/test/ELF/gnu-ifunc-i386.s +++ b/lld/test/ELF/gnu-ifunc-i386.s @@ -62,7 +62,7 @@ // CHECK-NEXT: } // CHECK-NEXT: Symbol { // CHECK-NEXT: Name: bar -// CHECK-NEXT: Value: 0x401110 +// CHECK-NEXT: Value: 0x401100 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global // CHECK-NEXT: Type: Function @@ -80,7 +80,7 @@ // CHECK-NEXT: } // CHECK-NEXT: Symbol { // CHECK-NEXT: Name: foo -// CHECK-NEXT: Value: 0x401100 +// CHECK-NEXT: Value: 0x401110 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global // CHECK-NEXT: Type: Function @@ -114,18 +114,18 @@ // DISASM: : // DISASM-NEXT: 4010e5: retl // DISASM: <_start>: -// DISASM-NEXT: 4010e6: calll 0x401100 -// DISASM-NEXT: calll 0x401110 +// DISASM-NEXT: 4010e6: calll 0x401110 +// DISASM-NEXT: calll 0x401100 // DISASM-NEXT: movl $4194516, %edx // DISASM-NEXT: movl $4194532, %edx // DISASM-EMPTY: // DISASM-NEXT: Disassembly of section .iplt: // DISASM-EMPTY: -// DISASM-NEXT: : +// DISASM-NEXT: : // DISASM-NEXT: 401100: jmpl *4202784 // DISASM-NEXT: pushl $0 // DISASM-NEXT: jmp 0x0 -// DISASM: : +// DISASM: : // DISASM-NEXT: 401110: jmpl *4202788 // DISASM-NEXT: pushl $8 // DISASM-NEXT: jmp 0x0 diff --git a/lld/test/ELF/ppc64-ifunc.s b/lld/test/ELF/ppc64-ifunc.s --- a/lld/test/ELF/ppc64-ifunc.s +++ b/lld/test/ELF/ppc64-ifunc.s @@ -16,9 +16,9 @@ # SYM: Value Size Type Bind Vis Ndx # SYM: 0000000010028298 0 NOTYPE LOCAL HIDDEN 4 .TOC. -# SYM: 0000000010010288 0 FUNC GLOBAL DEFAULT 3 ifunc1 +# SYM: 0000000010010268 0 FUNC GLOBAL DEFAULT 3 ifunc1 # SYM: 0000000010010210 0 IFUNC GLOBAL DEFAULT 2 ifunc2 -# SYM: 0000000010010278 0 FUNC GLOBAL DEFAULT 3 ifunc3 +# SYM: 0000000010010288 0 FUNC GLOBAL DEFAULT 3 ifunc3 # SECTIONS: .plt NOBITS 00000000100302a0 0002a0 000018 00 WA 0 0 8 @@ -32,23 +32,23 @@ # CHECK-NEXT: 10010224: bl 0x10010254 # CHECK-NEXT: ld 2, 24(1) # CHECK-NEXT: addis 3, 2, -2 +# CHECK-NEXT: addi 3, 3, 32720 +# CHECK-NEXT: addis 3, 2, -2 # CHECK-NEXT: addi 3, 3, 32752 -# CHECK-NEXT: addis 3, 2, -2 -# CHECK-NEXT: addi 3, 3, 32736 - -# .plt[0] - .TOC. = 0x100302a0 - 0x10028298 = (1<<16) - 32760 -# CHECK: <__plt_ifunc2>: -# CHECK-NEXT: std 2, 24(1) -# CHECK-NEXT: addis 12, 2, 1 -# CHECK-NEXT: ld 12, -32760(12) -# CHECK-NEXT: mtctr 12 -# CHECK-NEXT: bctr # .plt[1] - .TOC. = 0x100302a0+8 - 0x10028298 = (1<<16) - 32752 +# CHECK: <__plt_ifunc2>: +# CHECK-NEXT: std 2, 24(1) +# CHECK-NEXT: addis 12, 2, 1 +# CHECK-NEXT: ld 12, -32752(12) +# CHECK-NEXT: mtctr 12 +# CHECK-NEXT: bctr + +# .plt[2] - .TOC. = 0x100302a0+16 - 0x10028298 = (1<<16) - 32744 # CHECK: <__plt_ifunc3>: # CHECK-NEXT: std 2, 24(1) # CHECK-NEXT: addis 12, 2, 1 -# CHECK-NEXT: ld 12, -32752(12) +# CHECK-NEXT: ld 12, -32744(12) # CHECK-NEXT: mtctr 12 # CHECK-NEXT: bctr # CHECK-EMPTY: @@ -57,19 +57,17 @@ ## ifunc2 and ifunc3 have the same code sequence as their PLT call stubs. # CHECK: Disassembly of section .glink: # CHECK-EMPTY: -# CHECK-NEXT: 0000000010010268 <.glink>: +# CHECK-NEXT: 0000000010010268 : # CHECK-NEXT: addis 12, 2, 1 # CHECK-NEXT: ld 12, -32760(12) # CHECK-NEXT: mtctr 12 # CHECK-NEXT: bctr -# CHECK-EMPTY: -# CHECK-NEXT: 0000000010010278 : # CHECK-NEXT: addis 12, 2, 1 # CHECK-NEXT: ld 12, -32752(12) # CHECK-NEXT: mtctr 12 # CHECK-NEXT: bctr # CHECK-EMPTY: -# CHECK-NEXT: 0000000010010288 : +# CHECK-NEXT: 0000000010010288 : # CHECK-NEXT: addis 12, 2, 1 # CHECK-NEXT: ld 12, -32744(12) # CHECK-NEXT: mtctr 12 diff --git a/lld/test/ELF/symver.s b/lld/test/ELF/symver.s --- a/lld/test/ELF/symver.s +++ b/lld/test/ELF/symver.s @@ -105,8 +105,8 @@ # RUN: llvm-objdump -d --no-show-raw-insn %t.w1 | FileCheck %s --check-prefix=W1DIS # W1REL: .rela.plt { -# W1REL-NEXT: R_X86_64_JUMP_SLOT __wrap_foo 0x0 # W1REL-NEXT: R_X86_64_JUMP_SLOT foo@@v1 0x0 +# W1REL-NEXT: R_X86_64_JUMP_SLOT __wrap_foo 0x0 # W1REL-NEXT: } # W1DIS-LABEL: <.text>: @@ -121,8 +121,8 @@ # RUN: llvm-objdump -d --no-show-raw-insn %t.w2 | FileCheck %s --check-prefix=W2DIS # W2REL: .rela.plt { -# W2REL-NEXT: R_X86_64_JUMP_SLOT __wrap_foo 0x0 # W2REL-NEXT: R_X86_64_JUMP_SLOT foo@v1 0x0 +# W2REL-NEXT: R_X86_64_JUMP_SLOT __wrap_foo 0x0 # W2REL-NEXT: } # W2DIS-LABEL: <.text>: diff --git a/lld/test/ELF/wrap-plt.s b/lld/test/ELF/wrap-plt.s --- a/lld/test/ELF/wrap-plt.s +++ b/lld/test/ELF/wrap-plt.s @@ -10,8 +10,8 @@ // CHECK: Relocations [ // CHECK-NEXT: Section ({{.*}}) .rela.plt { -// CHECK-NEXT: R_X86_64_JUMP_SLOT __wrap_foo 0x0 // CHECK-NEXT: R_X86_64_JUMP_SLOT foo 0x0 +// CHECK-NEXT: R_X86_64_JUMP_SLOT __wrap_foo 0x0 // CHECK-NEXT: R_X86_64_JUMP_SLOT _start 0x0 // CHECK-NEXT: } // CHECK-NEXT: ] diff --git a/lld/test/ELF/x86-64-plt.s b/lld/test/ELF/x86-64-plt.s --- a/lld/test/ELF/x86-64-plt.s +++ b/lld/test/ELF/x86-64-plt.s @@ -14,15 +14,15 @@ # CHECK1: .plt PROGBITS 00000000002012e0 0002e0 000030 00 AX 0 0 16 # CHECK1: .got.plt PROGBITS 00000000002033e0 0003e0 000028 00 WA 0 0 8 # CHECK1: Relocation section '.rela.plt' at offset {{.*}} contains 2 entries: -# CHECK1: 00000000002033f8 {{.*}} R_X86_64_JUMP_SLOT 0000000000000000 bar + 0 -# CHECK1-NEXT: 0000000000203400 {{.*}} R_X86_64_JUMP_SLOT 0000000000000000 weak + 0 +# CHECK1: 00000000002033f8 {{.*}} R_X86_64_JUMP_SLOT 0000000000000000 weak + 0 +# CHECK1-NEXT: 0000000000203400 {{.*}} R_X86_64_JUMP_SLOT 0000000000000000 bar + 0 # CHECK2: Name Type Address Off Size ES Flg Lk Inf Al # CHECK2: .plt PROGBITS 0000000000001310 000310 000030 00 AX 0 0 16 # CHECK2: .got.plt PROGBITS 0000000000003400 000400 000028 00 WA 0 0 8 # CHECK2: Relocation section '.rela.plt' at offset {{.*}} contains 2 entries: -# CHECK2: 0000000000003418 {{.*}} R_X86_64_JUMP_SLOT 0000000000000000 bar + 0 -# CHECK2-NEXT: 0000000000003420 {{.*}} R_X86_64_JUMP_SLOT 0000000000000000 weak + 0 +# CHECK2: 0000000000003418 {{.*}} R_X86_64_JUMP_SLOT 0000000000000000 weak + 0 +# CHECK2-NEXT: 0000000000003420 {{.*}} R_X86_64_JUMP_SLOT 0000000000000000 bar + 0 # DISASM: <_start>: # DISASM-NEXT: callq {{.*}} @@ -37,12 +37,12 @@ # DISASM1-NEXT: jmpq *8452(%rip) # 0x2033f0 # DISASM1-NEXT: nopl (%rax) # DISASM1-EMPTY: -# DISASM1-NEXT: : +# DISASM1-NEXT: : # DISASM1-NEXT: 2012f0: jmpq *8450(%rip) # 0x2033f8 # DISASM1-NEXT: pushq $0 # DISASM1-NEXT: jmp 0x2012e0 <.plt> # DISASM1-EMPTY: -# DISASM1-NEXT: : +# DISASM1-NEXT: : # DISASM1-NEXT: 201300: jmpq *8442(%rip) # 0x203400 # DISASM1-NEXT: pushq $1 # DISASM1-NEXT: jmp 0x2012e0 <.plt> @@ -55,12 +55,12 @@ # DISASM2-NEXT: jmpq *8436(%rip) # 0x3410 # DISASM2-NEXT: nopl (%rax) # DISASM2-EMPTY: -# DISASM2-NEXT: : +# DISASM2-NEXT: : # DISASM2-NEXT: 1320: jmpq *8434(%rip) # 0x3418 # DISASM2-NEXT: pushq $0 # DISASM2-NEXT: jmp 0x1310 <.plt> # DISASM2-EMPTY: -# DISASM2-NEXT: : +# DISASM2-NEXT: : # DISASM2-NEXT: 1330: jmpq *8426(%rip) # 0x3420 # DISASM2-NEXT: pushq $1 # DISASM2-NEXT: jmp 0x1310 <.plt>