aboutsummaryrefslogtreecommitdiff
path: root/lib/Driver/Tools.cpp
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2012-11-19 03:52:03 +0000
committerChandler Carruth <chandlerc@gmail.com>2012-11-19 03:52:03 +0000
commit7ce816a77dc79f71950e9e96185e3523ee08994b (patch)
tree7f67df8bba1799c9bbdef2ed29a7910ee2107ae5 /lib/Driver/Tools.cpp
parent72511f3adcc89a29c02e36283536beadf9ef555e (diff)
Completely re-work how the Clang driver interprets PIC and PIE options.
There were numerous issues here that were all entangled, and so I've tried to do a general simplification of the logic. 1) The logic was mimicing actual GCC bugs, rather than "features". These have been fixed in trunk GCC, and this fixes Clang as well. Notably, the logic was always intended to be last-match-wins like any other flag. 2) The logic for handling '-mdynamic-no-pic' was preposterously unclear. It also allowed the use of this flag on non-Darwin platforms where it has no actual meaning. Now this option is handled directly based on tests of how llvm-gcc behaves, and it is only supported on Darwin. 3) The APIs for the Driver's ToolChains had the implementation ugliness of dynamic-no-pic leaking through them. They also had the implementation details of the LLVM relocation model flag names leaking through. 4) The actual results of passing these flags was incorrect on Darwin in many cases. For example, Darwin *always* uses PIC level 2 if it uses in PIC level, and Darwin *always* uses PIC on 64-bit regardless of the flags specified, including -fPIE. Darwin never compiles in PIE mode, but it can *link* in PIE mode. 5) Also, PIC was not always being enabled even when PIE was. This isn't a supported mode at all and may have caused some fallout in builds with complex PIC and PIE interactions. The result is (I hope) cleaner and clearer for readers. I've also left comments and tests about some of the truly strage behavior that is observed on Darwin platforms. We have no real testing of Windows platforms and PIC, but I don't have the tools handy to figure that out. Hopefully others can beef up our testing here. Unfortunately, I can't test this for every platform. =/ If folks have dependencies on these flags that aren't covered by tests, they may break. I've audited and ensured that all the changes in behavior of the existing tests are intentional and good. In particular I've tried to make sure the Darwin behavior (which is more suprising than the Linux behavior) also matches that of 'gcc' on my mac. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@168297 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Driver/Tools.cpp')
-rw-r--r--lib/Driver/Tools.cpp141
1 files changed, 74 insertions, 67 deletions
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 01bcf48485..e37959be4e 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1769,38 +1769,46 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CheckCodeGenerationOptions(D, Args);
- // Perform argument translation for LLVM backend. This
- // takes some care in reconciling with llvm-gcc. The
- // issue is that llvm-gcc translates these options based on
- // the values in cc1, whereas we are processing based on
- // the driver arguments.
-
- // This comes from the default translation the driver + cc1
- // would do to enable flag_pic.
-
- Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
- options::OPT_fpic, options::OPT_fno_pic);
- // We need to check for PIE flags separately because they can override the
- // PIC flags.
- Arg *LastPIEArg = Args.getLastArg(options::OPT_fPIE, options::OPT_fno_PIE,
- options::OPT_fpie, options::OPT_fno_pie);
- bool PICDisabled = false;
- bool PICEnabled = false;
- bool PICForPIE = false;
- if (LastPIEArg) {
- PICForPIE = (LastPIEArg->getOption().matches(options::OPT_fPIE) ||
- LastPIEArg->getOption().matches(options::OPT_fpie));
- }
- if (LastPICArg || PICForPIE) {
- // The last PIE enabled argument can infer that PIC is enabled.
- PICEnabled = (PICForPIE ||
- LastPICArg->getOption().matches(options::OPT_fPIC) ||
- LastPICArg->getOption().matches(options::OPT_fpic));
- // We need to have PICDisabled inside the if statement because on darwin
- // PIC is enabled by default even if PIC arguments are not in the command
- // line (in this case causes PICDisabled to be true).
- PICDisabled = !PICEnabled;
+ // For the PIC and PIE flag options, this logic is different from the legacy
+ // logic in very old versions of GCC, as that logic was just a bug no one had
+ // ever fixed. This logic is both more rational and consistent with GCC's new
+ // logic now that the bugs are fixed. The last argument relating to either
+ // PIC or PIE wins, and no other argument is used. If the last argument is
+ // any flavor of the '-fno-...' arguments, both PIC and PIE are disabled. Any
+ // PIE option implicitly enables PIC at the same level.
+ bool PIE = false;
+ bool PIC = getToolChain().isPICDefault();
+ bool IsPICLevelTwo = PIC;
+ if (Arg *A = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
+ options::OPT_fpic, options::OPT_fno_pic,
+ options::OPT_fPIE, options::OPT_fno_PIE,
+ options::OPT_fpie, options::OPT_fno_pie)) {
+ Option O = A->getOption();
+ if (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) ||
+ O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) {
+ PIE = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie);
+ PIC = PIE || O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic);
+ IsPICLevelTwo = O.matches(options::OPT_fPIE) ||
+ O.matches(options::OPT_fPIC);
+ } else {
+ PIE = PIC = false;
+ }
}
+ // Check whether the tool chain trumps the PIC-ness decision. If the PIC-ness
+ // is forced, then neither PIC nor PIE flags will have no effect.
+ if (getToolChain().isPICDefaultForced()) {
+ PIE = false;
+ PIC = getToolChain().isPICDefault();
+ IsPICLevelTwo = PIC;
+ }
+
+ // Inroduce a Darwin-specific hack. If the default is PIC but the flags
+ // specified while enabling PIC enabled level 1 PIC, just force it back to
+ // level 2 PIC instead. This matches the behavior of Darwin GCC (based on my
+ // informal testing).
+ if (PIC && getToolChain().getTriple().isOSDarwin())
+ IsPICLevelTwo |= getToolChain().isPICDefault();
+
// Note that these flags are trump-cards. Regardless of the order w.r.t. the
// PIC or PIE options above, if these show up, PIC is disabled.
llvm::Triple Triple(TripleStr);
@@ -1808,44 +1816,43 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.hasArg(options::OPT_fapple_kext)) &&
(Triple.getOS() != llvm::Triple::IOS ||
Triple.isOSVersionLT(6)))
- PICDisabled = true;
+ PIC = PIE = false;
if (Args.hasArg(options::OPT_static))
- PICDisabled = true;
- bool DynamicNoPIC = Args.hasArg(options::OPT_mdynamic_no_pic);
-
- // Select the relocation model.
- const char *Model = getToolChain().GetForcedPicModel();
- if (!Model) {
- if (DynamicNoPIC)
- Model = "dynamic-no-pic";
- else if (PICDisabled)
- Model = "static";
- else if (PICEnabled)
- Model = "pic";
- else
- Model = getToolChain().GetDefaultRelocationModel();
- }
- StringRef ModelStr = Model ? Model : "";
- if (Model && ModelStr != "pic") {
+ PIC = PIE = false;
+
+ if (Arg *A = Args.getLastArg(options::OPT_mdynamic_no_pic)) {
+ // This is a very special mode. It trumps the other modes, almost no one
+ // uses it, and it isn't even valid on any OS but Darwin.
+ if (!getToolChain().getTriple().isOSDarwin())
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getSpelling() << getToolChain().getTriple().str();
+
+ // FIXME: Warn when this flag trumps some other PIC or PIE flag.
+
CmdArgs.push_back("-mrelocation-model");
- CmdArgs.push_back(Model);
- }
-
- // Infer the __PIC__ and __PIE__ values.
- if (ModelStr == "pic" && PICForPIE) {
- CmdArgs.push_back("-pic-level");
- CmdArgs.push_back((LastPIEArg &&
- LastPIEArg->getOption().matches(options::OPT_fPIE)) ?
- "2" : "1");
- CmdArgs.push_back("-pie-level");
- CmdArgs.push_back((LastPIEArg &&
- LastPIEArg->getOption().matches(options::OPT_fPIE)) ?
- "2" : "1");
- } else if (ModelStr == "pic" || ModelStr == "dynamic-no-pic") {
- CmdArgs.push_back("-pic-level");
- CmdArgs.push_back(((ModelStr != "dynamic-no-pic" && LastPICArg &&
- LastPICArg->getOption().matches(options::OPT_fPIC)) ||
- getToolChain().getTriple().isOSDarwin()) ? "2" : "1");
+ CmdArgs.push_back("dynamic-no-pic");
+
+ // Only a forced PIC mode can cause the actual compile to have PIC defines
+ // etc., no flags are sufficient. This behavior was selected to closely
+ // match that of llvm-gcc and Apple GCC before that.
+ if (getToolChain().isPICDefault() && getToolChain().isPICDefaultForced()) {
+ CmdArgs.push_back("-pic-level");
+ CmdArgs.push_back("2");
+ }
+ } else {
+ // Currently, LLVM only knows about PIC vs. static; the PIE differences are
+ // handled in Clang's IRGen by the -pie-level flag.
+ CmdArgs.push_back("-mrelocation-model");
+ CmdArgs.push_back(PIC ? "pic" : "static");
+
+ if (PIC) {
+ CmdArgs.push_back("-pic-level");
+ CmdArgs.push_back(IsPICLevelTwo ? "2" : "1");
+ if (PIE) {
+ CmdArgs.push_back("-pie-level");
+ CmdArgs.push_back(IsPICLevelTwo ? "2" : "1");
+ }
+ }
}
if (!Args.hasFlag(options::OPT_fmerge_all_constants,