@@ -8,7 +8,7 @@ use rustc_middle::ty::{Instance, Ty, TyCtxt, TypeVisitableExt};
88use rustc_middle:: { bug, ty} ;
99use rustc_span:: sym;
1010use rustc_target:: callconv:: { ArgAbi , FnAbi , PassMode } ;
11- use rustc_target:: spec:: { Arch , BinaryFormat } ;
11+ use rustc_target:: spec:: { Arch , BinaryFormat , Env , Os } ;
1212
1313use crate :: common;
1414use crate :: mir:: AsmCodegenMethods ;
@@ -128,6 +128,8 @@ fn prefix_and_suffix<'tcx>(
128128
129129 let is_arm = tcx. sess . target . arch == Arch :: Arm ;
130130 let is_thumb = tcx. sess . unstable_target_features . contains ( & sym:: thumb_mode) ;
131+ let function_sections =
132+ tcx. sess . opts . unstable_opts . function_sections . unwrap_or ( tcx. sess . target . function_sections ) ;
131133
132134 // If we're compiling the compiler-builtins crate, e.g., the equivalent of
133135 // compiler-rt, then we want to implicitly compile everything with hidden
@@ -218,8 +220,6 @@ fn prefix_and_suffix<'tcx>(
218220 let mut end = String :: new ( ) ;
219221 match asm_binary_format {
220222 BinaryFormat :: Elf => {
221- let section = link_section. unwrap_or_else ( || format ! ( ".text.{asm_name}" ) ) ;
222-
223223 let progbits = match is_arm {
224224 true => "%progbits" ,
225225 false => "@progbits" ,
@@ -230,7 +230,13 @@ fn prefix_and_suffix<'tcx>(
230230 false => "@function" ,
231231 } ;
232232
233- writeln ! ( begin, ".pushsection {section},\" ax\" , {progbits}" ) . unwrap ( ) ;
233+ if let Some ( section) = & link_section {
234+ writeln ! ( begin, ".pushsection {section},\" ax\" , {progbits}" ) . unwrap ( ) ;
235+ } else if function_sections {
236+ writeln ! ( begin, ".pushsection .text.{asm_name},\" ax\" , {progbits}" ) . unwrap ( ) ;
237+ } else {
238+ writeln ! ( begin, ".text" ) . unwrap ( ) ;
239+ }
234240 writeln ! ( begin, ".balign {align_bytes}" ) . unwrap ( ) ;
235241 write_linkage ( & mut begin) . unwrap ( ) ;
236242 match visibility {
@@ -249,14 +255,22 @@ fn prefix_and_suffix<'tcx>(
249255 // pattern match on assembly generated by LLVM.
250256 writeln ! ( end, ".Lfunc_end_{asm_name}:" ) . unwrap ( ) ;
251257 writeln ! ( end, ".size {asm_name}, . - {asm_name}" ) . unwrap ( ) ;
252- writeln ! ( end, ".popsection" ) . unwrap ( ) ;
258+ if link_section. is_some ( ) || function_sections {
259+ writeln ! ( end, ".popsection" ) . unwrap ( ) ;
260+ }
253261 if !arch_suffix. is_empty ( ) {
254262 writeln ! ( end, "{}" , arch_suffix) . unwrap ( ) ;
255263 }
256264 }
257265 BinaryFormat :: MachO => {
258- let section = link_section. unwrap_or_else ( || "__TEXT,__text" . to_string ( ) ) ;
259- writeln ! ( begin, ".pushsection {},regular,pure_instructions" , section) . unwrap ( ) ;
266+ // NOTE: LLVM ignores `-Zfunction-sections` on macos. Instead the Mach-O symbol
267+ // subsection splitting feature is used, which can be enabled with the
268+ // `.subsections_via_symbols` global directive. LLVM already enables this directive.
269+ if let Some ( section) = & link_section {
270+ writeln ! ( begin, ".pushsection {section},regular,pure_instructions" ) . unwrap ( ) ;
271+ } else {
272+ writeln ! ( begin, ".section __TEXT,__text,regular,pure_instructions" ) . unwrap ( ) ;
273+ }
260274 writeln ! ( begin, ".balign {align_bytes}" ) . unwrap ( ) ;
261275 write_linkage ( & mut begin) . unwrap ( ) ;
262276 match visibility {
@@ -267,7 +281,9 @@ fn prefix_and_suffix<'tcx>(
267281
268282 writeln ! ( end) . unwrap ( ) ;
269283 writeln ! ( end, ".Lfunc_end_{asm_name}:" ) . unwrap ( ) ;
270- writeln ! ( end, ".popsection" ) . unwrap ( ) ;
284+ if link_section. is_some ( ) {
285+ writeln ! ( end, ".popsection" ) . unwrap ( ) ;
286+ }
271287 if !arch_suffix. is_empty ( ) {
272288 writeln ! ( end, "{}" , arch_suffix) . unwrap ( ) ;
273289 }
@@ -278,8 +294,36 @@ fn prefix_and_suffix<'tcx>(
278294 writeln ! ( begin, ".type 32" ) . unwrap ( ) ;
279295 writeln ! ( begin, ".endef" ) . unwrap ( ) ;
280296
281- let section = link_section. unwrap_or_else ( || format ! ( ".text.{asm_name}" ) ) ;
282- writeln ! ( begin, ".pushsection {},\" xr\" " , section) . unwrap ( ) ;
297+ if let Some ( section) = & link_section {
298+ writeln ! ( begin, ".section {section},\" xr\" " ) . unwrap ( )
299+ } else if !function_sections {
300+ // Function sections are enabled by default on MSVC and windows-gnullvm,
301+ // but disabled by default on GNU.
302+ writeln ! ( begin, ".text" ) . unwrap ( ) ;
303+ } else {
304+ // LLVM uses an extension to the section directive to support defining multiple
305+ // sections with the same name and comdat. It adds `unique,<id>` at the end of the
306+ // `.section` directive. We have no way of generating that unique ID here, so don't
307+ // emit it.
308+ //
309+ // See https://llvm.org/docs/Extensions.html#id2.
310+ match & tcx. sess . target . options . env {
311+ Env :: Gnu => {
312+ writeln ! ( begin, ".section .text${asm_name},\" xr\" ,one_only,{asm_name}" )
313+ . unwrap ( ) ;
314+ }
315+ Env :: Msvc => {
316+ writeln ! ( begin, ".section .text,\" xr\" ,one_only,{asm_name}" ) . unwrap ( ) ;
317+ }
318+ Env :: Unspecified => match & tcx. sess . target . options . os {
319+ Os :: Uefi => {
320+ writeln ! ( begin, ".section .text,\" xr\" ,one_only,{asm_name}" ) . unwrap ( ) ;
321+ }
322+ _ => bug ! ( "unexpected coff target {}" , tcx. sess. target. llvm_target) ,
323+ } ,
324+ other => bug ! ( "unexpected coff env {other:?}" ) ,
325+ }
326+ }
283327 write_linkage ( & mut begin) . unwrap ( ) ;
284328 writeln ! ( begin, ".balign {align_bytes}" ) . unwrap ( ) ;
285329 writeln ! ( begin, "{asm_name}:" ) . unwrap ( ) ;
0 commit comments