Skip to content
Merged
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
52 changes: 39 additions & 13 deletions compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rustc_data_structures::stable_hasher::StableHasher;
use rustc_hashes::Hash128;
use rustc_hir::attrs::NativeLibKind;
use rustc_session::Session;
use rustc_session::cstore::DllImport;
use rustc_session::cstore::{DllImport, DllImportSymbolType};
use rustc_span::Symbol;
use rustc_target::spec::Arch;

Expand Down Expand Up @@ -95,14 +95,14 @@ pub(super) fn create_raw_dylib_dll_import_libs<'a>(
true,
)
}),
is_data: !import.is_fn,
is_data: import.symbol_type != DllImportSymbolType::Function,
}
} else {
ImportLibraryItem {
name: import.name.to_string(),
ordinal: import.ordinal(),
symbol_name: None,
is_data: !import.is_fn,
is_data: import.symbol_type != DllImportSymbolType::Function,
}
}
})
Expand Down Expand Up @@ -271,10 +271,10 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
vers.push((version_name, dynstr));
id
};
syms.push((name, dynstr, Some(ver), symbol.is_fn));
syms.push((name, dynstr, Some(ver), symbol.symbol_type, symbol.size));
} else {
let dynstr = stub.add_dynamic_string(symbol_name.as_bytes());
syms.push((symbol_name, dynstr, None, symbol.is_fn));
syms.push((symbol_name, dynstr, None, symbol.symbol_type, symbol.size));
}
}

Expand All @@ -296,6 +296,8 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
stub.reserve_shstrtab_section_index();
let text_section_name = stub.add_section_name(".text".as_bytes());
let text_section = stub.reserve_section_index();
let data_section_name = stub.add_section_name(".data".as_bytes());
let data_section = stub.reserve_section_index();
stub.reserve_dynsym_section_index();
stub.reserve_dynstr_section_index();
if !vers.is_empty() {
Expand Down Expand Up @@ -375,7 +377,7 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
// Section headers
stub.write_null_section_header();
stub.write_shstrtab_section_header();
// Create a dummy .text section for our dummy symbols.
// Create a dummy .text section for our dummy non-data symbols.
stub.write_section_header(&write::SectionHeader {
name: Some(text_section_name),
sh_type: elf::SHT_PROGBITS,
Expand All @@ -385,7 +387,20 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
sh_size: 0,
sh_link: 0,
sh_info: 0,
sh_addralign: 1,
sh_addralign: 16,
sh_entsize: 0,
});
// And also a dummy .data section for our dummy data symbols.
stub.write_section_header(&write::SectionHeader {
name: Some(data_section_name),
sh_type: elf::SHT_PROGBITS,
sh_flags: (elf::SHF_WRITE | elf::SHF_ALLOC) as u64,
sh_addr: 0,
sh_offset: 0,
sh_size: 0,
sh_link: 0,
sh_info: 0,
sh_addralign: 16,
sh_entsize: 0,
});
stub.write_dynsym_section_header(0, 1);
Expand All @@ -398,17 +413,28 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]

// .dynsym
stub.write_null_dynamic_symbol();
for (_name, dynstr, _ver, is_fn) in syms.iter().copied() {
let sym_type = if is_fn { elf::STT_FUNC } else { elf::STT_NOTYPE };
// Linkers like LLD require at least somewhat reasonable symbol values rather than zero,
// otherwise all the symbols might get put at the same address. Thus we increment the value
// every time we write a symbol.
let mut st_value = 0;
for (_name, dynstr, _ver, symbol_type, size) in syms.iter().copied() {
let sym_type = match symbol_type {
DllImportSymbolType::Function => elf::STT_FUNC,
DllImportSymbolType::Static => elf::STT_OBJECT,
DllImportSymbolType::ThreadLocal => elf::STT_TLS,
};
let section =
if symbol_type == DllImportSymbolType::Static { data_section } else { text_section };
stub.write_dynamic_symbol(&write::Sym {
name: Some(dynstr),
st_info: (elf::STB_GLOBAL << 4) | sym_type,
st_other: elf::STV_DEFAULT,
section: Some(text_section),
section: Some(section),
st_shndx: 0, // ignored by object in favor of the `section` field
st_value: 0,
st_size: 0,
st_value,
st_size: size.bytes(),
});
st_value += 8;
}

// .dynstr
Expand All @@ -418,7 +444,7 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
if !vers.is_empty() {
// .gnu_version
stub.write_null_gnu_versym();
for (_name, _dynstr, ver, _is_fn) in syms.iter().copied() {
for (_name, _dynstr, ver, _symbol_type, _size) in syms.iter().copied() {
stub.write_gnu_versym(if let Some(ver) = ver {
assert!((2 + ver as u16) < elf::VERSYM_HIDDEN);
elf::VERSYM_HIDDEN | (2 + ver as u16)
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_codegen_ssa/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use rustc_hir::attrs::PeImportNameType;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, Instance, TyCtxt};
use rustc_middle::{bug, mir, span_bug};
use rustc_session::cstore::{DllCallingConvention, DllImport};
use rustc_session::cstore::{DllCallingConvention, DllImport, DllImportSymbolType};
use rustc_span::Span;
use rustc_target::spec::{Abi, Env, Os, Target};

Expand Down Expand Up @@ -199,15 +199,15 @@ pub fn i686_decorated_name(
decorated_name.push('\x01');
}

let prefix = if add_prefix && dll_import.is_fn {
let prefix = if add_prefix && dll_import.symbol_type == DllImportSymbolType::Function {
match dll_import.calling_convention {
DllCallingConvention::C | DllCallingConvention::Vectorcall(_) => None,
DllCallingConvention::Stdcall(_) => (!mingw
|| dll_import.import_name_type == Some(PeImportNameType::Decorated))
.then_some('_'),
DllCallingConvention::Fastcall(_) => Some('@'),
}
} else if !dll_import.is_fn && !mingw {
} else if dll_import.symbol_type != DllImportSymbolType::Function && !mingw {
// For static variables, prefix with '_' on MSVC.
Some('_')
} else {
Expand All @@ -219,7 +219,7 @@ pub fn i686_decorated_name(

decorated_name.push_str(name);

if add_suffix && dll_import.is_fn {
if add_suffix && dll_import.symbol_type == DllImportSymbolType::Function {
use std::fmt::Write;

match dll_import.calling_convention {
Expand Down
41 changes: 33 additions & 8 deletions compiler/rustc_metadata/src/native_libs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@ use rustc_abi::ExternAbi;
use rustc_attr_parsing::eval_config_entry;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::attrs::{NativeLibKind, PeImportNameType};
use rustc_hir::def::DefKind;
use rustc_hir::find_attr;
use rustc_middle::bug;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::query::LocalCrate;
use rustc_middle::ty::{self, List, Ty, TyCtxt};
use rustc_session::Session;
use rustc_session::config::CrateType;
use rustc_session::cstore::{DllCallingConvention, DllImport, ForeignModule, NativeLib};
use rustc_session::cstore::{
DllCallingConvention, DllImport, DllImportSymbolType, ForeignModule, NativeLib,
};
use rustc_session::search_paths::PathKind;
use rustc_span::Symbol;
use rustc_span::def_id::{DefId, LOCAL_CRATE};
Expand Down Expand Up @@ -451,12 +456,32 @@ impl<'tcx> Collector<'tcx> {
}
}

DllImport {
name,
import_name_type,
calling_convention,
span,
is_fn: self.tcx.def_kind(item).is_fn_like(),
}
let def_kind = self.tcx.def_kind(item);
let symbol_type = if def_kind.is_fn_like() {
DllImportSymbolType::Function
} else if matches!(def_kind, DefKind::Static { .. }) {
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
DllImportSymbolType::ThreadLocal
} else {
DllImportSymbolType::Static
}
} else {
bug!("Unexpected type for raw-dylib: {}", def_kind.descr(item));
Copy link
Member

Choose a reason for hiding this comment

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

this is reachable via #154111

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, I have tried to use type there, but only as a definition. Not as a declaration, I'll look into it tomorrow.

};

let size = match symbol_type {
// We cannot determine the size of a function at compile time, but it shouldn't matter anyway.
DllImportSymbolType::Function => rustc_abi::Size::ZERO,
DllImportSymbolType::Static | DllImportSymbolType::ThreadLocal => {
let ty = self.tcx.type_of(item).instantiate_identity();
self.tcx
.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
.ok()
.map(|layout| layout.size)
.unwrap_or_else(|| bug!("Non-function symbols must have a size"))
}
};

DllImport { name, import_name_type, calling_convention, span, symbol_type, size }
}
}
11 changes: 9 additions & 2 deletions compiler/rustc_session/src/cstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,15 @@ pub struct DllImport {
pub calling_convention: DllCallingConvention,
/// Span of import's "extern" declaration; used for diagnostics.
pub span: Span,
/// Is this for a function (rather than a static variable).
pub is_fn: bool,
pub symbol_type: DllImportSymbolType,
pub size: rustc_abi::Size,
}

#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic, PartialEq)]
pub enum DllImportSymbolType {
Function,
Static,
ThreadLocal,
}

impl DllImport {
Expand Down
5 changes: 5 additions & 0 deletions tests/run-make/raw-dylib-elf/library.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
int global_variable = 3;
__thread int tls_variable = 33;
const long const_array[] = {795, 906};
const char *const_string = "sums of three cubes";

int this_is_a_library_function() {
return 42;
}
22 changes: 20 additions & 2 deletions tests/run-make/raw-dylib-elf/main.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
#![feature(raw_dylib_elf)]
#![feature(thread_local)]
#![allow(incomplete_features)]

use std::ffi::{CStr, c_char, c_int, c_long};

#[link(name = "library", kind = "raw-dylib")]
unsafe extern "C" {
safe fn this_is_a_library_function() -> core::ffi::c_int;
safe fn this_is_a_library_function() -> c_int;
static mut global_variable: c_int;
#[thread_local]
static mut tls_variable: c_int;
safe static const_array: [c_long; 2];
safe static const_string: *const c_char;
}

fn main() {
println!("{}", this_is_a_library_function())
unsafe {
println!(
"{} {} {} {} {} {}",
this_is_a_library_function(),
global_variable,
tls_variable,
const_array[0],
const_array[1],
CStr::from_ptr(const_string).to_str().unwrap(),
);
}
}
2 changes: 1 addition & 1 deletion tests/run-make/raw-dylib-elf/output.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
42
42 3 33 795 906 sums of three cubes
30 changes: 19 additions & 11 deletions tests/run-make/raw-dylib-elf/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,27 @@
use run_make_support::{build_native_dynamic_lib, cwd, diff, run, rustc};

fn main() {
// We compile the binary without having the library present.
// We compile the binaries without having the library present with different relocation
// models.
// We also set the rpath to the current directory so we can pick up the library at runtime.
rustc()
.crate_type("bin")
.input("main.rs")
.arg(&format!("-Wl,-rpath={}", cwd().display()))
.run();
let relocation_models = ["static", "pic", "pie"];
for relocation_model in relocation_models {
rustc()
.crate_type("bin")
.input("main.rs")
.arg(&format!("-Wl,-rpath={}", cwd().display()))
.arg(&format!("-Crelocation-model={}", relocation_model))
.output(&format!("main-{}", relocation_model))
.run();
}

// Now, *after* building the binary, we build the library...
// Now, *after* building the binaries, we build the library...
build_native_dynamic_lib("library");

// ... and run with this library, ensuring it was linked correctly at runtime.
let output = run("main").stdout_utf8();

diff().expected_file("output.txt").actual_text("actual", output).run();
for relocation_model in relocation_models {
// ... and run with this library, ensuring it was linked correctly at runtime.
// The output here should be the same regardless of the relocation model.
let output = run(&format!("main-{}", relocation_model)).stdout_utf8();
diff().expected_file("output.txt").actual_text("actual", output).run();
}
}
Loading