Index: test/MC/ELF/reloc-subsection.s =================================================================== --- test/MC/ELF/reloc-subsection.s (revision 0) +++ test/MC/ELF/reloc-subsection.s (revision 0) @@ -0,0 +1,326 @@ +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux %s -o %t +// RUN: llvm-objdump -r %t | FileCheck %s + +// /* Create references that normally would use section-relative relocs +// ** (or be resolved without a relocation, for local .text references) +// ** but with dead-stripping will be using the actual symbols: +// ** - call a static func in the same .text section +// ** - refer to a static data item from .text section +// ** - refer to a static data item from the same .data section +// ** - refer to a constant in .rodata +// ** Verify .debug_info still does use section-relative relocs. +// */ +// static int local_func() { return 1; } +// static double static_dbl = 1.23456789987654321; +// static double *static_ptr = &static_dbl; +// int reloc_test() { +// *static_ptr = 9.87654321123456789; +// return local_func(); +// } + + .subsections_via_symbols + .file "reloc-subsection.c" + .file 1 "reloc-subsection.c" + .section .debug_info,"",@progbits +.Lsection_info: + .section .debug_abbrev,"",@progbits +.Lsection_abbrev: + .section .debug_aranges,"",@progbits + .section .debug_macinfo,"",@progbits + .section .debug_line,"",@progbits +.Lsection_line: + .section .debug_loc,"",@progbits + .section .debug_pubtypes,"",@progbits + .section .debug_str,"MS",@progbits,1 +.Lsection_str: + .section .debug_ranges,"",@progbits +.Ldebug_range: + .section .debug_loc,"",@progbits +.Lsection_debug_loc: + .text +.Ltext_begin: + .data + .section .rodata.cst8,"aM",@progbits,8 + .align 8 +.LCPI0_0: + .quad 4621749617595486475 # double 9.876543e+00 + # (0x4023c0ca4593910b) + .text + .globl reloc_test + .align 16, 0x90 + .type reloc_test,@function +reloc_test: # @reloc_test + .cfi_startproc +.Lfunc_begin0: + .loc 1 12 0 # reloc-subsection.c:12:0 +# BB#0: # %entry + pushq %rbp +.Ltmp2: + .cfi_def_cfa_offset 16 +.Ltmp3: + .cfi_offset %rbp, -16 + movq %rsp, %rbp +.Ltmp4: + .cfi_def_cfa_register %rbp + vmovsd .LCPI0_0, %xmm0 + .loc 1 13 3 prologue_end # reloc-subsection.c:13:3 +.Ltmp5: + movq static_ptr, %rax + vmovsd %xmm0, (%rax) + .loc 1 14 10 # reloc-subsection.c:14:10 + callq local_func + popq %rbp + ret +.Ltmp6: +.Ltmp7: + .size reloc_test, .Ltmp7-reloc_test +.Lfunc_end0: + .cfi_endproc + + .align 16, 0x90 + .type local_func,@function +local_func: # @local_func + .cfi_startproc +.Lfunc_begin1: + .loc 1 9 0 # reloc-subsection.c:9:0 +# BB#0: # %entry + movl $1, %eax + .loc 1 9 27 prologue_end # reloc-subsection.c:9:27 +.Ltmp8: + ret +.Ltmp9: +.Ltmp10: + .size local_func, .Ltmp10-local_func +.Lfunc_end1: + .cfi_endproc + + .type static_ptr,@object # @static_ptr + .data + .align 8 +static_ptr: + .quad static_dbl + .size static_ptr, 8 + + .type static_dbl,@object # @static_dbl + .align 8 +static_dbl: + .quad 4608238818706494488 # double 1.234568e+00 + # (0x3ff3c0ca452a9418) + .size static_dbl, 8 + + .text +.Ltext_end: + .data +.Ldata_end: + .text +.Lsection_end1: + .section .debug_info,"",@progbits +.Linfo_begin1: + .long 154 # Length of Compilation Unit Info + .short 2 # DWARF version number + .long .Labbrev_begin # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x93 DW_TAG_compile_unit + .long .Lstring0 # DW_AT_producer + .short 12 # DW_AT_language + .long .Lstring1 # DW_AT_name + .quad 0 # DW_AT_low_pc + .long .Lsection_line # DW_AT_stmt_list + .long .Lstring2 # DW_AT_comp_dir + .byte 2 # Abbrev [2] 0x26:0x7 DW_TAG_base_type + .long .Lstring4 # DW_AT_name + .byte 4 # DW_AT_encoding + .byte 8 # DW_AT_byte_size + .byte 3 # Abbrev [3] 0x2d:0x5 DW_TAG_pointer_type + .long 38 # DW_AT_type + .byte 4 # Abbrev [4] 0x32:0x15 DW_TAG_variable + .long .Lstring3 # DW_AT_name + .long 45 # DW_AT_type + .byte 1 # DW_AT_decl_file + .byte 11 # DW_AT_decl_line + .byte 9 # DW_AT_location + .byte 3 + .quad static_ptr + .byte 4 # Abbrev [4] 0x47:0x15 DW_TAG_variable + .long .Lstring5 # DW_AT_name + .long 38 # DW_AT_type + .byte 1 # DW_AT_decl_file + .byte 10 # DW_AT_decl_line + .byte 9 # DW_AT_location + .byte 3 + .quad static_dbl + .byte 5 # Abbrev [5] 0x5c:0x1d DW_TAG_subprogram + .long .Lstring6 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 12 # DW_AT_decl_line + .long 121 # DW_AT_type + # DW_AT_external + .quad .Lfunc_begin0 # DW_AT_low_pc + .quad .Lfunc_end0 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .byte 2 # Abbrev [2] 0x79:0x7 DW_TAG_base_type + .long .Lstring7 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 6 # Abbrev [6] 0x80:0x1d DW_TAG_subprogram + .long .Lstring8 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 9 # DW_AT_decl_line + .long 121 # DW_AT_type + .quad .Lfunc_begin1 # DW_AT_low_pc + .quad .Lfunc_end1 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 87 + # DW_AT_APPLE_omit_frame_ptr + .byte 0 # End Of Children Mark +.Linfo_end1: + .section .debug_abbrev,"",@progbits +.Labbrev_begin: + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 14 # DW_FORM_strp + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 16 # DW_AT_stmt_list + .byte 6 # DW_FORM_data4 + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 15 # DW_TAG_pointer_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 2 # DW_AT_location + .byte 10 # DW_FORM_block1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 1 # DW_FORM_addr + .byte 64 # DW_AT_frame_base + .byte 10 # DW_FORM_block1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 1 # DW_FORM_addr + .byte 64 # DW_AT_frame_base + .byte 10 # DW_FORM_block1 + .ascii "\347\177" # DW_AT_APPLE_omit_frame_ptr + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) +.Labbrev_end: + .section .debug_aranges,"",@progbits + .section .debug_ranges,"",@progbits + .section .debug_macinfo,"",@progbits + .section .debug_str,"MS",@progbits,1 +.Lstring0: + .asciz "clang version 3.3 (trunk 175138)" +.Lstring1: + .asciz "reloc-subsection.c" +.Lstring2: + .asciz "/home/probinson/projects/subsection" +.Lstring3: + .asciz "static_ptr" +.Lstring4: + .asciz "double" +.Lstring5: + .asciz "static_dbl" +.Lstring6: + .asciz "reloc_test" +.Lstring7: + .asciz "int" +.Lstring8: + .asciz "local_func" + + .section ".note.GNU-stack","",@progbits + +// References from .text and .data should use func/variable names. +// References from other sections should use section-relative relocations. + +// CHECK: RELOCATION RECORDS FOR [.text] +// CHECK-NEXT: .LCPI0_0+0 +// CHECK-NEXT: static_ptr+0 +// CHECK-NEXT: local_func-4 + +// CHECK: RELOCATION RECORDS FOR [.data] +// CHECK-NEXT: static_dbl+0 + +// FIXME: For some reason we are still seeing .debug_info refs to .data +// using var+0 instead of .data+N, so don't check those. +// CHECK: RELOCATION RECORDS FOR [.debug_info] +// NOT: static_ptr +// NOT: static_dbl +// CHECK-NOT: local_func +// CHECK-NOT: reloc_test +// Also no temp-symbol references. +// CHECK-NOT: .L + +// CHECK: RELOCATION RECORDS FOR [.debug_line] +// CHECK-NOT: local_func +// CHECK-NOT: reloc_test + +// CHECK: RELOCATION RECORDS FOR [.eh_frame] +// CHECK-NOT: local_func +// CHECK-NOT: reloc_test Index: test/MC/AsmParser/directive_subsections_via_symbols.s =================================================================== --- test/MC/AsmParser/directive_subsections_via_symbols.s (revision 177604) +++ test/MC/AsmParser/directive_subsections_via_symbols.s (working copy) @@ -1,4 +1,5 @@ # RUN: llvm-mc -triple i386-apple-darwin9 %s | FileCheck %s +# RUN: llvm-mc -triple i386-pc-linux %s | FileCheck %s # CHECK: TEST0: # CHECK: .subsections_via_symbols Index: include/llvm/MC/MCDirectives.h =================================================================== --- include/llvm/MC/MCDirectives.h (revision 177604) +++ include/llvm/MC/MCDirectives.h (working copy) @@ -46,7 +46,7 @@ enum MCAssemblerFlag { MCAF_SyntaxUnified, ///< .syntax (ARM/ELF) - MCAF_SubsectionsViaSymbols, ///< .subsections_via_symbols (MachO) + MCAF_SubsectionsViaSymbols, ///< .subsections_via_symbols (MachO,ELF) MCAF_Code16, ///< .code16 (X86) / .code 16 (ARM) MCAF_Code32, ///< .code32 (X86) / .code 32 (ARM) MCAF_Code64 ///< .code64 (X86) Index: lib/MC/ELFObjectWriter.cpp =================================================================== --- lib/MC/ELFObjectWriter.cpp (revision 177604) +++ lib/MC/ELFObjectWriter.cpp (working copy) @@ -682,12 +682,28 @@ return &Symbol; } + // If dead-stripping, function and variable references + // should not be converted to .section+offset. + if (Asm.getSubsectionsViaSymbols() && !Symbol.isTemporary()) { + uint32_t Type = MCELF::GetType(SD); + if (Type == ELF::STT_FUNC || Type == ELF::STT_OBJECT) { + if (Renamed) + return Renamed; + return &Symbol; + } + } + if (Section.getFlags() & ELF::SHF_MERGE) { - if (Target.getConstant() == 0) - return ExplicitRelSym(Asm, Target, F, Fixup, IsPCRel); - if (Renamed) - return Renamed; - return &Symbol; + // In an SHF_MERGE section, keep the original symbol if: + // - it's symbol+N for non-zero N; or, + // - we're dead-stripping, and 'symbol' isn't in a .debug* section. + if (Target.getConstant() != 0 || + (Asm.getSubsectionsViaSymbols() && + !Section.getSectionName().startswith(".debug"))) { + if (Renamed) + return Renamed; + return &Symbol; + } } return ExplicitRelSym(Asm, Target, F, Fixup, IsPCRel); @@ -1583,6 +1599,18 @@ bool IsPCRel) const { if (DataA.getFlags() & ELF_STB_Weak) return false; + + if (Asm.getSubsectionsViaSymbols()) { + // For dead-stripping, we don't resolve non-temp references to + // variables and functions. + const MCSymbol &SA = DataA.getSymbol().AliasedSymbol(); + unsigned ELFType = MCELF::GetType(DataA); + if (!SA.isTemporary() && + (ELFType == ELF::STT_OBJECT || ELFType == ELF::STT_FUNC)) + return false; + } + + return MCObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl( Asm, DataA, FB,InSet, IsPCRel); } Index: lib/MC/MCParser/ELFAsmParser.cpp =================================================================== --- lib/MC/MCParser/ELFAsmParser.cpp (revision 177604) +++ lib/MC/MCParser/ELFAsmParser.cpp (working copy) @@ -76,6 +76,8 @@ &ELFAsmParser::ParseDirectiveSymbolAttribute>(".internal"); addDirectiveHandler< &ELFAsmParser::ParseDirectiveSymbolAttribute>(".hidden"); + addDirectiveHandler<&ELFAsmParser::ParseDirectiveSubsectionsViaSymbols>( + ".subsections_via_symbols"); } // FIXME: Part of this logic is duplicated in the MCELFStreamer. What is @@ -147,6 +149,7 @@ bool ParseDirectiveVersion(StringRef, SMLoc); bool ParseDirectiveWeakref(StringRef, SMLoc); bool ParseDirectiveSymbolAttribute(StringRef, SMLoc); + bool ParseDirectiveSubsectionsViaSymbols(StringRef, SMLoc); private: bool ParseSectionName(StringRef &SectionName); @@ -613,6 +616,18 @@ return false; } +/// ParseDirectiveSubsectionsViaSymbols +/// ::= .subsections_via_symbols +bool ELFAsmParser::ParseDirectiveSubsectionsViaSymbols(StringRef, SMLoc) { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.subsections_via_symbols' directive"); + + Lex(); + + getStreamer().EmitAssemblerFlag(MCAF_SubsectionsViaSymbols); + return false; +} + namespace llvm { MCAsmParserExtension *createELFAsmParser() {