Skip to content

[clang] [MinGW] Explicitly always pass the -fno-use-init-array #68571

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 10, 2023

Conversation

mstorsjo
Copy link
Member

@mstorsjo mstorsjo commented Oct 9, 2023

On MinGW targets, the .ctors section is always used for constructors.

Make sure that all layers of code generation is aware of this, wherever it matters, by passing the -fno-use-init-array option, setting the TargetOptions field UseInitArray to false.

This fixes #55938.

On MinGW targets, the .ctors section is always used for constructors.

Make sure that all layers of code generation is aware of this,
wherever it matters, by passing the -fno-use-init-array option,
setting the TargetOptions field UseInitArray to false.

This fixes llvm#55938.
@mstorsjo mstorsjo added clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' platform:windows labels Oct 9, 2023
@llvmbot llvmbot added the clang Clang issues not falling into any other category label Oct 9, 2023
@llvmbot
Copy link
Member

llvmbot commented Oct 9, 2023

@llvm/pr-subscribers-clang
@llvm/pr-subscribers-platform-windows

@llvm/pr-subscribers-clang-driver

Changes

On MinGW targets, the .ctors section is always used for constructors.

Make sure that all layers of code generation is aware of this, wherever it matters, by passing the -fno-use-init-array option, setting the TargetOptions field UseInitArray to false.

This fixes #55938.


Full diff: https://github.com/llvm/llvm-project/pull/68571.diff

2 Files Affected:

  • (modified) clang/lib/Driver/ToolChains/MinGW.cpp (+2)
  • (modified) clang/test/Driver/mingw.cpp (+3)
diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp
index 5872e13bda358f8..d3d829a8ddbdb95 100644
--- a/clang/lib/Driver/ToolChains/MinGW.cpp
+++ b/clang/lib/Driver/ToolChains/MinGW.cpp
@@ -709,6 +709,8 @@ void toolchains::MinGW::addClangTargetOptions(
     }
   }
 
+  CC1Args.push_back("-fno-use-init-array");
+
   for (auto Opt : {options::OPT_mthreads, options::OPT_mwindows,
                    options::OPT_mconsole, options::OPT_mdll}) {
     if (Arg *A = DriverArgs.getLastArgNoClaim(Opt))
diff --git a/clang/test/Driver/mingw.cpp b/clang/test/Driver/mingw.cpp
index 0f276820d0fff22..bb22a0652b486e1 100644
--- a/clang/test/Driver/mingw.cpp
+++ b/clang/test/Driver/mingw.cpp
@@ -77,3 +77,6 @@
 // CHECK_NO_SUBSYS-NOT: "--subsystem"
 // CHECK_SUBSYS_CONSOLE: "--subsystem" "console"
 // CHECK_SUBSYS_WINDOWS: "--subsystem" "windows"
+
+// RUN: %clang -target i686-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_NO_INIT_ARRAY %s
+// CHECK_NO_INIT_ARRAY: "-fno-use-init-array"

@mstorsjo
Copy link
Member Author

mstorsjo commented Oct 9, 2023

This is an alternative to #68570. This has the upside that the UseInitArray flag is set to the correct value throughout the chain, for any other potential users of the field, in case it would affect code generation in other places. The downside is that if we only go with this, then any other language frontend, which might not know about the details about .ctors, will end up with the same bug unless they also add a similar fix. (We could of course go with both fixes as well.)

@efriedma-quic
Copy link
Collaborator

We could go with a clang fix, but also make the backend report_fatal_error if you try to use llvm.ctors with UseInitArray on mingw. That keeps everything consistent while also making sure non-clang frontends don't miscompile.

@mstorsjo
Copy link
Member Author

mstorsjo commented Oct 9, 2023

We could go with a clang fix, but also make the backend report_fatal_error if you try to use llvm.ctors with UseInitArray on mingw. That keeps everything consistent while also making sure non-clang frontends don't miscompile.

Hmm, interesting proposition... But wouldn't that essentially break every single invocation of llc with a mingw triple, unless they also explicitly pass the -use-ctors option? And for any other language frontend, I also feel that it would, somewhat abruptly, break every single current user of LLVM for mingw targets, unless they update their calling code to explicitly set UseInitArray to false for this target?

@efriedma-quic
Copy link
Collaborator

Hmm...

Maybe the backend should have some notion of a default ctors section. So if the frontend doesn't explicitly specify anything, the backend tries to pick the right default.

@mstorsjo
Copy link
Member Author

mstorsjo commented Oct 9, 2023

Hmm...

Maybe the backend should have some notion of a default ctors section. So if the frontend doesn't explicitly specify anything, the backend tries to pick the right default.

Yep, this is kinda the same issue for lots of target specific options that are set as bools..., while the ideal I guess either would be an optional<bool>, or to initialize the bools to the target specific actual value.

In this case, I would maybe suggest merging both this and #68570 - that should both fix behaviours and make clang aware of the reality, and leave the root design issue for someone else to take on... WDYT?

@efriedma-quic
Copy link
Collaborator

Doesn't UseInitArray default to false in LLVM?

Anyway, we already have ways to make booleans optional; it's just a matter of implementing a "default" state, which we already do for certain options like code models. I don't think there's any fundamental architectural work involved in doing that. (See various enums in TargetOptions.h)

@mstorsjo
Copy link
Member Author

mstorsjo commented Oct 9, 2023

Doesn't UseInitArray default to false in LLVM?

The class TargetOptions itself initializes it to false indeed. But codegen::InitTargetOptionsFromCodeGenFlags (which seems to be what e.g. llc uses) explicitly sets it to !getUseCtors(), which only checks the state of the -use-ctors option. And Clang sets it unconditionally based on the codegen option with the same name, which defaults to true and is controlled by the -f[no-]use-init-array option.

Anyway, we already have ways to make booleans optional; it's just a matter of implementing a "default" state, which we already do for certain options like code models. I don't think there's any fundamental architectural work involved in doing that. (See various enums in TargetOptions.h)

Right, so adding an enum DefaultableBool { Default, False, True } and changing the field to that value? That'd be an API break for all users of the struct, but which should be allowed for us to do? All users of TargetOptions would need to change from passing regular bools to passing values from this enum - and at the same time, they get reminded that they can keep it set to Default in case they don't really have a strong opinion on the matter. Is that what you had in mind? Or is there a way to make the migration smoother for users somehow?

It sounds like a somewhat disruptive change for downstreams; I know we're not supposed to compromise upstream design too much around downstream concerns, but it feels somewhat like making more of a fuss than I wanted...

@efriedma-quic
Copy link
Collaborator

It's only breaking for downstreams that were messing with the option in the first place. Searching GitHub, the only downstream I can find that actually touches it is rustc.

I understand it's simpler to just override the behavior for MinGW, but I think it's really confusing to have an option in TargetOptions that's arbitrarily ignored by some targets (both for developers reading the code, and for users).

Copy link
Collaborator

@efriedma-quic efriedma-quic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whatever we decide to do on the LLVM side, this seems fine for the clang side. It looks like clang uses the value of UseInitArray for some ObjC stuff, in addition to passing it to the backend, so we need the right value in clang in any case.

@mstorsjo
Copy link
Member Author

mstorsjo commented Oct 9, 2023

Right, so adding an enum DefaultableBool { Default, False, True } and changing the field to that value?

With such a definition, I wonder how to interpret it for MSVC targets; UseInitArray would be false, as MSVC uses the .CRT sections, neither .ctors not .init_array. But it shouldn’t be reversed, and false currently means reversing it.

@efriedma-quic
Copy link
Collaborator

On targets that don't use the Unix .ctors/.init_array convention, the option doesn't make any sense, so we should just ignore it. For example, the AIX target overrides emitXXStructorList.

@mstorsjo
Copy link
Member Author

Whatever we decide to do on the LLVM side, this seems fine for the clang side.

Yes, this bit should be fine in any case.

It looks like clang uses the value of UseInitArray for some ObjC stuff, in addition to passing it to the backend, so we need the right value in clang in any case.

Indeed, having the correct picture is good, if there's logic that depends on it. For the ObjC case, the code actually looks like this:

    if (CGM.getTriple().isOSBinFormatCOFF())
        InitVar->setSection(".CRT$XCLz");
    else
    {
      if (CGM.getCodeGenOpts().UseInitArray)
        InitVar->setSection(".init_array");
      else
        InitVar->setSection(".ctors");
    }

So in that sense, it doesn't really matter here. (The .CRT$... sections do work on mingw too, even if .ctors normally is used.)

tru pushed a commit that referenced this pull request Oct 16, 2023
On MinGW targets, the .ctors section is always used for constructors.

When using the .ctors section, the constructors need to be emitted in
reverse order to get them execute in the right order. (Constructors with
a specific priority are sorted separately by the linker later.) In LLVM,
in CodeGen/AsmPrinter/AsmPrinter.cpp, there's code that reverses them
before writing them out, executed when using the .ctors section. This
logic is done whenever TM.Options.UseInitArray is set to false. Thus,
make sure to set UseInitArray to false for this target.

This fixes #55938.

(cherry picked from commit a2b8c49)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang Clang issues not falling into any other category platform:windows
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[MSYS2] Ordered dynamic initialization is not sequenced
3 participants