Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions example/mini_core_hello_world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,16 @@ fn main() {
naked_test();
}

// Test global_asm sym operand - calls sym_target() via assembly
#[cfg(all(
not(jit),
any(target_arch = "x86_64", target_arch = "aarch64"),
any(target_os = "linux", target_os = "macos")
))]
unsafe {
assert_eq!(global_asm_sym_test(), 42);
}

// Both statics have a reference that points to the same anonymous allocation.
static REF1: &u8 = &42;
static REF2: &u8 = REF1;
Expand Down Expand Up @@ -361,6 +371,15 @@ unsafe extern "C" {
fn global_asm_test();
}

#[cfg(all(
not(jit),
any(target_arch = "x86_64", target_arch = "aarch64"),
any(target_os = "linux", target_os = "macos")
))]
unsafe extern "C" {
fn global_asm_sym_test() -> u64;
}

#[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))]
global_asm! {
"
Expand All @@ -381,6 +400,57 @@ global_asm! {
"
}

// Test global_asm sym operands - the function referenced via sym may be private
// to the codegen unit, so we create a wrapper function.
#[cfg(all(
not(jit),
any(target_arch = "x86_64", target_arch = "aarch64"),
any(target_os = "linux", target_os = "macos")
))]
fn sym_target() -> u64 {
42
}

#[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))]
global_asm! {
"
.global global_asm_sym_test
global_asm_sym_test:
jmp {sym_fn}
",
sym_fn = sym sym_target,
}

#[cfg(all(not(jit), target_arch = "x86_64", target_os = "macos"))]
global_asm! {
"
.global _global_asm_sym_test
_global_asm_sym_test:
jmp {sym_fn}
",
sym_fn = sym sym_target,
}

#[cfg(all(not(jit), target_arch = "aarch64", target_os = "linux"))]
global_asm! {
"
.global global_asm_sym_test
global_asm_sym_test:
b {sym_fn}
",
sym_fn = sym sym_target,
}

#[cfg(all(not(jit), target_arch = "aarch64", target_os = "macos"))]
global_asm! {
"
.global _global_asm_sym_test
_global_asm_sym_test:
b {sym_fn}
",
sym_fn = sym sym_target,
}

#[cfg(all(not(jit), target_arch = "x86_64"))]
#[unsafe(naked)]
extern "C" fn naked_test() {
Expand Down
18 changes: 16 additions & 2 deletions src/driver/aot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,8 @@ fn codegen_cgu_content(

let mut debug_context = DebugContext::new(tcx, module.isa(), false, cgu_name.as_str());
let mut global_asm = String::new();
let mut global_asm_sym_index = 0u32;
let target_config = module.target_config();
let mut type_dbg = TypeDebugContext::default();
super::predefine_mono_items(tcx, module, &mono_items);
let mut codegened_functions = vec![];
Expand All @@ -527,7 +529,13 @@ fn codegen_cgu_content(
let flags = tcx.codegen_instance_attrs(instance.def).flags;
if flags.contains(CodegenFnAttrFlags::NAKED) {
rustc_codegen_ssa::mir::naked_asm::codegen_naked_asm(
&mut GlobalAsmContext { tcx, global_asm: &mut global_asm },
&mut GlobalAsmContext {
tcx,
global_asm: &mut global_asm,
module,
target_config,
global_asm_sym_index: &mut global_asm_sym_index,
},
instance,
MonoItemData {
linkage: RLinkage::External,
Expand Down Expand Up @@ -560,7 +568,13 @@ fn codegen_cgu_content(
}
MonoItem::GlobalAsm(item_id) => {
rustc_codegen_ssa::base::codegen_global_asm(
&mut GlobalAsmContext { tcx, global_asm: &mut global_asm },
&mut GlobalAsmContext {
tcx,
global_asm: &mut global_asm,
module,
target_config,
global_asm_sym_index: &mut global_asm_sym_index,
},
item_id,
);
}
Expand Down
46 changes: 42 additions & 4 deletions src/global_asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::path::PathBuf;
use std::process::{Command, Stdio};
use std::sync::Arc;

use cranelift_codegen::isa::TargetFrontendConfig;
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_codegen_ssa::traits::{AsmCodegenMethods, GlobalAsmOperandRef};
use rustc_middle::ty::TyCtxt;
Expand All @@ -15,11 +16,17 @@ use rustc_middle::ty::layout::{
use rustc_session::config::{OutputFilenames, OutputType};
use rustc_target::asm::InlineAsmArch;

use crate::abi::get_function_sig;
use crate::common::create_wrapper_function;
use crate::prelude::*;

pub(crate) struct GlobalAsmContext<'a, 'tcx> {
pub tcx: TyCtxt<'tcx>,
pub global_asm: &'a mut String,
pub module: &'a mut dyn Module,
pub target_config: TargetFrontendConfig,
/// Counter for generating unique wrapper names
pub global_asm_sym_index: &'a mut u32,
}

impl<'tcx> AsmCodegenMethods<'tcx> for GlobalAsmContext<'_, 'tcx> {
Expand All @@ -30,7 +37,16 @@ impl<'tcx> AsmCodegenMethods<'tcx> for GlobalAsmContext<'_, 'tcx> {
options: InlineAsmOptions,
_line_spans: &[Span],
) {
codegen_global_asm_inner(self.tcx, self.global_asm, template, operands, options);
codegen_global_asm_inner(
self.tcx,
self.global_asm,
self.module,
self.target_config,
self.global_asm_sym_index,
template,
operands,
options,
);
}

fn mangled_name(&self, instance: Instance<'tcx>) -> String {
Expand Down Expand Up @@ -89,11 +105,15 @@ impl<'tcx> HasTypingEnv<'tcx> for GlobalAsmContext<'_, 'tcx> {
fn codegen_global_asm_inner<'tcx>(
tcx: TyCtxt<'tcx>,
global_asm: &mut String,
module: &mut dyn Module,
target_config: TargetFrontendConfig,
global_asm_sym_index: &mut u32,
template: &[InlineAsmTemplatePiece],
operands: &[GlobalAsmOperandRef<'tcx>],
options: InlineAsmOptions,
) {
let is_x86 = matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64);
let is_macho = tcx.sess.target.is_like_darwin;

if is_x86 {
if !options.contains(InlineAsmOptions::ATT_SYNTAX) {
Expand All @@ -119,9 +139,22 @@ fn codegen_global_asm_inner<'tcx>(
}

let symbol = tcx.symbol_name(instance);
// FIXME handle the case where the function was made private to the
// current codegen unit
global_asm.push_str(symbol.name);

// Pass a wrapper rather than the function itself as the function itself
// may not be exported from the main codegen unit and may thus be
// unreachable from the object file created by an external assembler.
let wrapper_name =
format!("__global_asm_sym_wrapper{}", *global_asm_sym_index);
*global_asm_sym_index += 1;
let sig =
get_function_sig(tcx, target_config.default_call_conv, instance);
create_wrapper_function(module, sig, &wrapper_name, symbol.name);

// For Mach-O, symbols need an underscore prefix
if is_macho {
global_asm.push('_');
}
global_asm.push_str(&wrapper_name);
}
GlobalAsmOperandRef::SymStatic { def_id } => {
if cfg!(not(feature = "inline_asm_sym")) {
Expand All @@ -133,6 +166,11 @@ fn codegen_global_asm_inner<'tcx>(

let instance = Instance::mono(tcx, def_id);
let symbol = tcx.symbol_name(instance);
// For statics, we reference them directly as they should be visible.
// Add Mach-O underscore prefix if needed.
if is_macho {
global_asm.push('_');
}
global_asm.push_str(symbol.name);
}
}
Expand Down
8 changes: 7 additions & 1 deletion src/inline_asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,13 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
CInlineAsmOperand::Const { ref value } => {
generated_asm.push_str(value);
}
CInlineAsmOperand::Symbol { ref symbol } => generated_asm.push_str(symbol),
CInlineAsmOperand::Symbol { ref symbol } => {
// For Mach-O, symbols need an underscore prefix
if binary_format == BinaryFormat::Macho {
generated_asm.push('_');
}
generated_asm.push_str(symbol);
}
}
}
}
Expand Down
Loading