Andrea Vezzosi pushed to branch wip/andrea/splitsections at Glasgow Haskell Compiler / GHC Commits: 4aa3f2d1 by Andrea Vezzosi at 2026-11-03T12:43:38+01:00 driver: Don't let -dynamic unset -fsplit-sections `addWay' WayDyn` used to unset Opt_SplitSections, so -fsplit-sections was ignored if it came before -dynamic, but worked if it came after. The -fsplit-sections -dynamic combination has legitimate uses, e.g. an executable can be linked dynamically against libraries and still have dead code from its own sources to eliminate. Or the same objects could be used for both static archives and shared objects. The removal of Opt_SplitSections was also motivated by problems on Darwin. It is now done in `makeDynFlagsConsistent` instead, see Note [Split sections are not supported on Mach-O]. For consistency, we also keep Opt_SplitSections when `dynamicNow` is activated. There is a cost of larger .dyn_o (but not .so) files and slower link times (esp. with ld.bfd), but does not seem significant enough to warrant special casing. Fixes #28061 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> - - - - - 13 changed files: - + changelog.d/split-sections-dynamic - compiler/GHC/Driver/Downsweep.hs - compiler/GHC/Driver/DynFlags.hs - compiler/GHC/Driver/Session.hs - compiler/GHC/Platform/Ways.hs - docs/users_guide/phases.rst - testsuite/tests/codeGen/should_gen_asm/all.T - + testsuite/tests/codeGen/should_gen_asm/split-sections-dynamic1.asm - + testsuite/tests/codeGen/should_gen_asm/split-sections-dynamic1.hs - + testsuite/tests/codeGen/should_gen_asm/split-sections-dynamic2.asm - + testsuite/tests/codeGen/should_gen_asm/split-sections-dynamic2.hs - testsuite/tests/llvm/should_compile/all.T - + testsuite/tests/llvm/should_compile/split-sections-darwin.hs Changes: ===================================== changelog.d/split-sections-dynamic ===================================== @@ -0,0 +1,14 @@ +section: compiler +synopsis: ``-fsplit-sections`` is no longer disabled by ``-dynamic`` +description: + ``-dynamic`` used to unset ``-fsplit-sections``, but only when + ``-fsplit-sections`` appeared earlier on the command line, so the flag meant + different things depending on the order of the two. Both orders now split + sections, as do the dynamic outputs of ``-dynamic-too``. + + On Darwin, ``-fsplit-sections`` is now always ignored with a warning: Mach-O + has poor support for split sections and instead offers + ``.subsections_via_symbols``, which GHC uses where it's able to. + +mrs: !16915 +issues: #28061 ===================================== compiler/GHC/Driver/Downsweep.hs ===================================== @@ -1638,10 +1638,7 @@ enableCodeGenWhen logger tmpfs staticLife dynLife unit_env mod_graph = do dflags_b = foldl gopt_set dflags_a $ concatMap (wayGeneralFlags platform) hostFullWays - dflags_c = foldl gopt_unset dflags_b - $ concatMap (wayUnsetGeneralFlags platform) - hostFullWays - in dflags_c + in dflags_b {- Note [-fno-code mode] ~~~~~~~~~~~~~~~~~~~~~~~~ ===================================== compiler/GHC/Driver/DynFlags.hs ===================================== @@ -1079,16 +1079,13 @@ dopt_unset dfs f = dfs{ dumpFlags = EnumSet.delete f (dumpFlags dfs) } -- | Test whether a 'GeneralFlag' is set -- -- Note that `dynamicNow` (i.e., dynamic objects built with `-dynamic-too`) --- always implicitly enables Opt_PIC, Opt_ExternalDynamicRefs, and disables --- Opt_SplitSections. +-- always implicitly enables Opt_PIC and Opt_ExternalDynamicRefs. -- gopt :: GeneralFlag -> DynFlags -> Bool gopt Opt_PIC dflags | dynamicNow dflags = True gopt Opt_ExternalDynamicRefs dflags | dynamicNow dflags = True -gopt Opt_SplitSections dflags - | dynamicNow dflags = False gopt f dflags = f `EnumSet.member` generalFlags dflags -- | Set a 'GeneralFlag' ===================================== compiler/GHC/Driver/Session.hs ===================================== @@ -2985,9 +2985,7 @@ addWay' w dflags0 = dflags1 = dflags0 { targetWays_ = addWay w (targetWays_ dflags0) } dflags2 = foldr setGeneralFlag' dflags1 (wayGeneralFlags platform w) - dflags3 = foldr unSetGeneralFlag' dflags2 - (wayUnsetGeneralFlags platform w) - in dflags3 + in dflags2 removeWayDynP :: Way -> DynP () removeWayDynP w = upd (\dfs -> dfs { targetWays_ = removeWay w (targetWays_ dfs) }) @@ -3806,6 +3804,20 @@ In the checks and fixes performed by `makeDynFlagsConsistent`, the choice between the two does not seem uniform. TODO: Make this choice more evident and uniform. -} +{- Note [Split sections are not supported on Darwin] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +On Darwin, split sections are either ignored by the backends (NCG, C) or would +cause errors (LLVM, see split-sections-darwin test). + +The `.subsections_via_symbols` feature of Mach-O is used instead (see Note +[Subsections Via Symbols]). This works on x86_64, but not yet on aarch64 (c.f +#24962 #23672). + +`makeDynFlagsConsistent` then disables split-sections on darwin unconditionally. +This is redundant on x86_64, because of the `platformHasSubsectionsViaSymbols` +check, but harmless. +-} + -- | Resolve any internal inconsistencies in a set of 'DynFlags'. -- Returns the consistent 'DynFlags' as well as a list of warnings -- to report to the user, and a list of verbose info msgs. @@ -3835,6 +3847,13 @@ makeDynFlagsConsistent dflags "since it uses subsections-via-symbols. Ignoring." in loop dflags' warn + -- See Note [Split sections are not supported on Mach-O] + | gopt Opt_SplitSections dflags + , os == OSDarwin + = let dflags' = gopt_unset dflags Opt_SplitSections + warn = "-fsplit-sections is not supported on Mach-O. Ignoring." + in loop dflags' warn + -- Via-C backend only supports unregisterised ABI. Switch to a backend -- supporting it if possible. | backendUnregisterisedAbiOnly (backend dflags) && @@ -3950,10 +3969,7 @@ makeDynFlagsConsistent dflags dflags_b = foldl gopt_set dflags_a $ concatMap (wayGeneralFlags platform) hostFullWays - dflags_c = foldl gopt_unset dflags_b - $ concatMap (wayUnsetGeneralFlags platform) - hostFullWays - in dflags_c + in dflags_b | gopt Opt_InfoTableMap dflags , NotValid msg <- backendInfoTableMapValidity (backend dflags) ===================================== compiler/GHC/Platform/Ways.hs ===================================== @@ -28,7 +28,6 @@ module GHC.Platform.Ways , removeWay , allowed_combination , wayGeneralFlags - , wayUnsetGeneralFlags , wayOptc , wayOptcxx , wayOptl @@ -164,16 +163,6 @@ wayGeneralFlags platform WayProf - https://gitlab.haskell.org/ghc/ghc/-/issues/26994 -} wayGeneralFlags _ WayProf = [] --- | Turn these flags off when enabling this way -wayUnsetGeneralFlags :: Platform -> Way -> [GeneralFlag] -wayUnsetGeneralFlags _ (WayCustom {}) = [] -wayUnsetGeneralFlags _ WayThreaded = [] -wayUnsetGeneralFlags _ WayDebug = [] -wayUnsetGeneralFlags _ WayDyn = [Opt_SplitSections] - -- There's no point splitting when we're going to be dynamically linking. - -- Plus it breaks compilation on OSX x86. -wayUnsetGeneralFlags _ WayProf = [] - -- | Pass these options to the C compiler when enabling this way wayOptc :: Platform -> Way -> [String] wayOptc _ (WayCustom {}) = [] ===================================== docs/users_guide/phases.rst ===================================== @@ -1063,6 +1063,10 @@ for example). When linking, the linker can automatically remove all unreferenced sections and thus produce smaller executables. + This flag is ignored on Darwin as the Mach-O object format is not suitable + for split sections. The ``.subsections_via_symbols`` directive and the + linker's ``-dead_strip`` are used where supported, regardless of this flag. + .. ghc-flag:: -static :shortdesc: Use static Haskell libraries :type: dynamic ===================================== testsuite/tests/codeGen/should_gen_asm/all.T ===================================== @@ -11,6 +11,22 @@ test('bytearray-memset-unroll', is_amd64_codegen, compile_grep_asm, ['hs', True, test('bytearray-memcpy-unroll', is_amd64_codegen, compile_grep_asm, ['hs', True, '']) test('T18137', [when(opsys('darwin'), skip), only_ways(llvm_ways)], compile_grep_asm, ['hs', False, '-fllvm -split-sections']) +# -fsplit-sections used to be silently unset by -dynamic, but only when it +# appeared before -dynamic on the command line. Check that both orders split. +# Mach-O has no split sections at all, and COFF names subsections with '$'. +split_sections_dynamic = [ + unless(have_dynamic(), skip), + when(opsys('darwin'), skip), + when(opsys('mingw32'), skip), + when(unregisterised(), skip), + only_ways(['normal']), +] + +test('split-sections-dynamic1', split_sections_dynamic, compile_grep_asm, + ['hs', False, '-fsplit-sections -dynamic']) +test('split-sections-dynamic2', split_sections_dynamic, compile_grep_asm, + ['hs', False, '-dynamic -fsplit-sections']) + test('T24941', [only_ways(['optasm'])], compile, ['-fregs-graph']) test('msse-option-order', [unless(arch('x86_64') or arch('i386'), skip), ===================================== testsuite/tests/codeGen/should_gen_asm/split-sections-dynamic1.asm ===================================== @@ -0,0 +1 @@ +\.section\s+\.text\.SplitSectionsDyn_ \ No newline at end of file ===================================== testsuite/tests/codeGen/should_gen_asm/split-sections-dynamic1.hs ===================================== @@ -0,0 +1,8 @@ +-- -fsplit-sections before -dynamic; split-sections-dynamic2 is the other order. +module SplitSectionsDyn (f, g) where + +f :: Int -> Int +f x = x + 1 + +g :: Int -> Int +g = (* 2) ===================================== testsuite/tests/codeGen/should_gen_asm/split-sections-dynamic2.asm ===================================== @@ -0,0 +1 @@ +\.section\s+\.text\.SplitSectionsDyn_ \ No newline at end of file ===================================== testsuite/tests/codeGen/should_gen_asm/split-sections-dynamic2.hs ===================================== @@ -0,0 +1,8 @@ +-- -dynamic before -fsplit-sections; split-sections-dynamic1 is the other order. +module SplitSectionsDyn (f, g) where + +f :: Int -> Int +f x = x + 1 + +g :: Int -> Int +g = (* 2) ===================================== testsuite/tests/llvm/should_compile/all.T ===================================== @@ -23,3 +23,8 @@ test('T17920fail', cmm_src, compile_fail, ['-no-hs-main']) test('T25019', unless((arch('x86_64') or arch('i386')) and have_cpu_feature('sse4_2'),skip), compile, ['-msse4.2']) test('T25353', unless((arch('x86_64') or arch('i386')) and have_cpu_feature('sse4_2'),skip), compile_grep_asm, ['hs', True, '-msse4.2']) test('T25606', normal, compile, ['']) + +test('split-sections-darwin', + [unless(opsys('darwin'), skip), + normalise_errmsg_fun(ignore_llvm_and_vortex)], + compile, ['-fsplit-sections -Wno-inconsistent-flags']) ===================================== testsuite/tests/llvm/should_compile/split-sections-darwin.hs ===================================== @@ -0,0 +1,13 @@ +-- -fsplit-sections must be ignored on Darwin; see +-- Note [Split sections are not supported on Mach-O] in GHC.Driver.Session. +-- +-- Mach-O cannot name a section after a symbol, so GHC ignores -fsplit-sections +-- on Darwin. Without that, llvmFunSection emits ELF-style ".text.<label>" names +-- and LLVM rejects them. Only reproduces on AArch64/Darwin: on +-- x86_64/Darwin the flag is already dropped for subsections-via-symbols. +-- -Wno-inconsistent-flags suppresses the "Ignoring" warning, whose wording +-- differs between the two Darwin platforms. +module SplitSectionsDarwin (f) where + +f :: Int -> Int +f x = x + 1 View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/4aa3f2d1f75cf179da36bc26745f29d4... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/4aa3f2d1f75cf179da36bc26745f29d4... You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
participants (1)
-
Andrea Vezzosi (@trac-Saizan)