llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.66k stars 11.85k forks source link

__attribute__((section())) not always honored in extern "C" under optimization #19131

Closed markmentovai closed 10 years ago

markmentovai commented 10 years ago
Bugzilla Link 18757
Resolution FIXED
Resolved on Feb 12, 2014 20:19
Version trunk
OS All
CC @nico,@rnk

Extended Description

When a static variable with attribute((section())) is placed inside extern "C", under optimization, the section attribute is not honored.

Consider this small test in C++:

extern "C" { static const int i attribute((used, section("DATA,custom"))) = 1; } // extern "C"

clang should place the data in the DATA,custom section. Instead, under optimization (-O1 or higher), it places it in the TEXT,const section.

My team experienced this problem when creating a DATA,interpose section for dyld interposing on Mac OS X. The interpose data was inadvertently placed inside an extern "C" block. Since it didn’t need to be extern "C", it was removed from this block and its attribute((section())) was honored properly.

This problem occurs with qualifiers “static const” and “const” alone (it is placed in TEXT,const), and with “static” alone (it is placed in DATA,data). When using “extern const”, “extern” alone, or no qualifiers, it is placed in the desired section (DATA,custom).

With no optimization (-O0), it is always placed in the desired section (DATA,custom) regardless of qualifiers and regardless of whether it’s inside an extern "C" block.

Outside of extern "C", regardless of qualifiers, at any optimization level, it is always properly placed in the desired section (DATA,custom). In plain C mode (no ++), it is also always properly placed in the desired section. (Some of these combinations do present a -Wextern-initializer warning.)

This bug is present in the current clang trunk (r200925). My Mac’s system copy of clang, which identifies itself as “Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)” from Xcode 5.0.2 5A3005, does not have this bug. I tested binary builds of clang I had on hand, and the bug is not present in r182481, but had regressed by r184830.

This example uses data, but similar problems were seen when attempting to place code into custom sections by decorating function definitions with attribute((section())).

Although the discussion above is obviously Mach-O-specific, this bug is not limited to Mach-O or Mac. Testing the current clang trunk on Linux, I see the same bug, with obvious substitutions for the sections used.

Test case:

-- extern "C" { static const int i attribute((used, section("DATA,custom"))) = 1; }

Compile with: clang++ -S test.cc -o- -O1

Expect:

-- .section TEXT,text,regular,pure_instructions .section DATA,custom .align 2 ## @​i _i: .long 1 ## 0x1

.no_dead_strip  _i

.subsections_via_symbols

Observe:

-- .section TEXT,text,regular,pure_instructions .section TEXT,const .align 2 ## @​i _i: .long 1 ## 0x1

.no_dead_strip  _i

.subsections_via_symbols

rnk commented 10 years ago

Thanks for the report. We're pretty sure this is a bug in globalopt, not clang, and r201286 should have fixed it.

markmentovai commented 10 years ago

Here’s a fix: http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20140203/098616.html .

markmentovai commented 10 years ago

I’ve bisected this to r183756. The bug is not present in r183755, and is in r183756.


r183756 | rafael | 2013-06-11 13:48:06 -0400 (Tue, 11 Jun 2013) | 21 lines

Change how globalopt handles aliases in llvm.used.

Instead of a custom implementation of replaceAllUsesWith, we just call replaceAllUsesWith and recreate llvm.used and llvm.compiler-used.

This change is particularity interesting because it makes llvm see through what clang is doing with static used functions in extern "C" contexts. With this change, running clang -O2 in

extern "C" { attribute((used)) static void foo() {} }

produces

@​llvm.used = appending global [1 x i8] [i8 bitcast (void () @​foo to i8)], section "llvm.metadata" define internal void @​foo() #​0 { entry: ret void }