Skip to content

Commit c0172a3

Browse files
authored
Rollup merge of #153580 - mati865:elf-raw-dylib-static-and-tls, r=bjorn3
Handle statics and TLS in raw-dylib for ELF Follow-up to #153090
2 parents a3903b1 + 3531ed9 commit c0172a3

8 files changed

Lines changed: 130 additions & 41 deletions

File tree

compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_data_structures::stable_hasher::StableHasher;
99
use rustc_hashes::Hash128;
1010
use rustc_hir::attrs::NativeLibKind;
1111
use rustc_session::Session;
12-
use rustc_session::cstore::DllImport;
12+
use rustc_session::cstore::{DllImport, DllImportSymbolType};
1313
use rustc_span::Symbol;
1414
use rustc_target::spec::Arch;
1515

@@ -95,14 +95,14 @@ pub(super) fn create_raw_dylib_dll_import_libs<'a>(
9595
true,
9696
)
9797
}),
98-
is_data: !import.is_fn,
98+
is_data: import.symbol_type != DllImportSymbolType::Function,
9999
}
100100
} else {
101101
ImportLibraryItem {
102102
name: import.name.to_string(),
103103
ordinal: import.ordinal(),
104104
symbol_name: None,
105-
is_data: !import.is_fn,
105+
is_data: import.symbol_type != DllImportSymbolType::Function,
106106
}
107107
}
108108
})
@@ -271,10 +271,10 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
271271
vers.push((version_name, dynstr));
272272
id
273273
};
274-
syms.push((name, dynstr, Some(ver), symbol.is_fn));
274+
syms.push((name, dynstr, Some(ver), symbol.symbol_type, symbol.size));
275275
} else {
276276
let dynstr = stub.add_dynamic_string(symbol_name.as_bytes());
277-
syms.push((symbol_name, dynstr, None, symbol.is_fn));
277+
syms.push((symbol_name, dynstr, None, symbol.symbol_type, symbol.size));
278278
}
279279
}
280280

@@ -296,6 +296,8 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
296296
stub.reserve_shstrtab_section_index();
297297
let text_section_name = stub.add_section_name(".text".as_bytes());
298298
let text_section = stub.reserve_section_index();
299+
let data_section_name = stub.add_section_name(".data".as_bytes());
300+
let data_section = stub.reserve_section_index();
299301
stub.reserve_dynsym_section_index();
300302
stub.reserve_dynstr_section_index();
301303
if !vers.is_empty() {
@@ -375,7 +377,7 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
375377
// Section headers
376378
stub.write_null_section_header();
377379
stub.write_shstrtab_section_header();
378-
// Create a dummy .text section for our dummy symbols.
380+
// Create a dummy .text section for our dummy non-data symbols.
379381
stub.write_section_header(&write::SectionHeader {
380382
name: Some(text_section_name),
381383
sh_type: elf::SHT_PROGBITS,
@@ -385,7 +387,20 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
385387
sh_size: 0,
386388
sh_link: 0,
387389
sh_info: 0,
388-
sh_addralign: 1,
390+
sh_addralign: 16,
391+
sh_entsize: 0,
392+
});
393+
// And also a dummy .data section for our dummy data symbols.
394+
stub.write_section_header(&write::SectionHeader {
395+
name: Some(data_section_name),
396+
sh_type: elf::SHT_PROGBITS,
397+
sh_flags: (elf::SHF_WRITE | elf::SHF_ALLOC) as u64,
398+
sh_addr: 0,
399+
sh_offset: 0,
400+
sh_size: 0,
401+
sh_link: 0,
402+
sh_info: 0,
403+
sh_addralign: 16,
389404
sh_entsize: 0,
390405
});
391406
stub.write_dynsym_section_header(0, 1);
@@ -398,17 +413,28 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
398413

399414
// .dynsym
400415
stub.write_null_dynamic_symbol();
401-
for (_name, dynstr, _ver, is_fn) in syms.iter().copied() {
402-
let sym_type = if is_fn { elf::STT_FUNC } else { elf::STT_NOTYPE };
416+
// Linkers like LLD require at least somewhat reasonable symbol values rather than zero,
417+
// otherwise all the symbols might get put at the same address. Thus we increment the value
418+
// every time we write a symbol.
419+
let mut st_value = 0;
420+
for (_name, dynstr, _ver, symbol_type, size) in syms.iter().copied() {
421+
let sym_type = match symbol_type {
422+
DllImportSymbolType::Function => elf::STT_FUNC,
423+
DllImportSymbolType::Static => elf::STT_OBJECT,
424+
DllImportSymbolType::ThreadLocal => elf::STT_TLS,
425+
};
426+
let section =
427+
if symbol_type == DllImportSymbolType::Static { data_section } else { text_section };
403428
stub.write_dynamic_symbol(&write::Sym {
404429
name: Some(dynstr),
405430
st_info: (elf::STB_GLOBAL << 4) | sym_type,
406431
st_other: elf::STV_DEFAULT,
407-
section: Some(text_section),
432+
section: Some(section),
408433
st_shndx: 0, // ignored by object in favor of the `section` field
409-
st_value: 0,
410-
st_size: 0,
434+
st_value,
435+
st_size: size.bytes(),
411436
});
437+
st_value += 8;
412438
}
413439

414440
// .dynstr
@@ -418,7 +444,7 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
418444
if !vers.is_empty() {
419445
// .gnu_version
420446
stub.write_null_gnu_versym();
421-
for (_name, _dynstr, ver, _is_fn) in syms.iter().copied() {
447+
for (_name, _dynstr, ver, _symbol_type, _size) in syms.iter().copied() {
422448
stub.write_gnu_versym(if let Some(ver) = ver {
423449
assert!((2 + ver as u16) < elf::VERSYM_HIDDEN);
424450
elf::VERSYM_HIDDEN | (2 + ver as u16)

compiler/rustc_codegen_ssa/src/common.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_hir::attrs::PeImportNameType;
55
use rustc_middle::ty::layout::TyAndLayout;
66
use rustc_middle::ty::{self, Instance, TyCtxt};
77
use rustc_middle::{bug, mir, span_bug};
8-
use rustc_session::cstore::{DllCallingConvention, DllImport};
8+
use rustc_session::cstore::{DllCallingConvention, DllImport, DllImportSymbolType};
99
use rustc_span::Span;
1010
use rustc_target::spec::{Abi, Env, Os, Target};
1111

@@ -199,15 +199,15 @@ pub fn i686_decorated_name(
199199
decorated_name.push('\x01');
200200
}
201201

202-
let prefix = if add_prefix && dll_import.is_fn {
202+
let prefix = if add_prefix && dll_import.symbol_type == DllImportSymbolType::Function {
203203
match dll_import.calling_convention {
204204
DllCallingConvention::C | DllCallingConvention::Vectorcall(_) => None,
205205
DllCallingConvention::Stdcall(_) => (!mingw
206206
|| dll_import.import_name_type == Some(PeImportNameType::Decorated))
207207
.then_some('_'),
208208
DllCallingConvention::Fastcall(_) => Some('@'),
209209
}
210-
} else if !dll_import.is_fn && !mingw {
210+
} else if dll_import.symbol_type != DllImportSymbolType::Function && !mingw {
211211
// For static variables, prefix with '_' on MSVC.
212212
Some('_')
213213
} else {
@@ -219,7 +219,7 @@ pub fn i686_decorated_name(
219219

220220
decorated_name.push_str(name);
221221

222-
if add_suffix && dll_import.is_fn {
222+
if add_suffix && dll_import.symbol_type == DllImportSymbolType::Function {
223223
use std::fmt::Write;
224224

225225
match dll_import.calling_convention {

compiler/rustc_metadata/src/native_libs.rs

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,17 @@ use rustc_abi::ExternAbi;
55
use rustc_attr_parsing::eval_config_entry;
66
use rustc_data_structures::fx::FxHashSet;
77
use rustc_hir::attrs::{NativeLibKind, PeImportNameType};
8+
use rustc_hir::def::DefKind;
89
use rustc_hir::find_attr;
10+
use rustc_middle::bug;
11+
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
912
use rustc_middle::query::LocalCrate;
1013
use rustc_middle::ty::{self, List, Ty, TyCtxt};
1114
use rustc_session::Session;
1215
use rustc_session::config::CrateType;
13-
use rustc_session::cstore::{DllCallingConvention, DllImport, ForeignModule, NativeLib};
16+
use rustc_session::cstore::{
17+
DllCallingConvention, DllImport, DllImportSymbolType, ForeignModule, NativeLib,
18+
};
1419
use rustc_session::search_paths::PathKind;
1520
use rustc_span::Symbol;
1621
use rustc_span::def_id::{DefId, LOCAL_CRATE};
@@ -451,12 +456,32 @@ impl<'tcx> Collector<'tcx> {
451456
}
452457
}
453458

454-
DllImport {
455-
name,
456-
import_name_type,
457-
calling_convention,
458-
span,
459-
is_fn: self.tcx.def_kind(item).is_fn_like(),
460-
}
459+
let def_kind = self.tcx.def_kind(item);
460+
let symbol_type = if def_kind.is_fn_like() {
461+
DllImportSymbolType::Function
462+
} else if matches!(def_kind, DefKind::Static { .. }) {
463+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
464+
DllImportSymbolType::ThreadLocal
465+
} else {
466+
DllImportSymbolType::Static
467+
}
468+
} else {
469+
bug!("Unexpected type for raw-dylib: {}", def_kind.descr(item));
470+
};
471+
472+
let size = match symbol_type {
473+
// We cannot determine the size of a function at compile time, but it shouldn't matter anyway.
474+
DllImportSymbolType::Function => rustc_abi::Size::ZERO,
475+
DllImportSymbolType::Static | DllImportSymbolType::ThreadLocal => {
476+
let ty = self.tcx.type_of(item).instantiate_identity();
477+
self.tcx
478+
.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
479+
.ok()
480+
.map(|layout| layout.size)
481+
.unwrap_or_else(|| bug!("Non-function symbols must have a size"))
482+
}
483+
};
484+
485+
DllImport { name, import_name_type, calling_convention, span, symbol_type, size }
461486
}
462487
}

compiler/rustc_session/src/cstore.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,15 @@ pub struct DllImport {
9797
pub calling_convention: DllCallingConvention,
9898
/// Span of import's "extern" declaration; used for diagnostics.
9999
pub span: Span,
100-
/// Is this for a function (rather than a static variable).
101-
pub is_fn: bool,
100+
pub symbol_type: DllImportSymbolType,
101+
pub size: rustc_abi::Size,
102+
}
103+
104+
#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic, PartialEq)]
105+
pub enum DllImportSymbolType {
106+
Function,
107+
Static,
108+
ThreadLocal,
102109
}
103110

104111
impl DllImport {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
int global_variable = 3;
2+
__thread int tls_variable = 33;
3+
const long const_array[] = {795, 906};
4+
const char *const_string = "sums of three cubes";
5+
16
int this_is_a_library_function() {
27
return 42;
38
}
Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,29 @@
11
#![feature(raw_dylib_elf)]
2+
#![feature(thread_local)]
23
#![allow(incomplete_features)]
34

5+
use std::ffi::{CStr, c_char, c_int, c_long};
6+
47
#[link(name = "library", kind = "raw-dylib")]
58
unsafe extern "C" {
6-
safe fn this_is_a_library_function() -> core::ffi::c_int;
9+
safe fn this_is_a_library_function() -> c_int;
10+
static mut global_variable: c_int;
11+
#[thread_local]
12+
static mut tls_variable: c_int;
13+
safe static const_array: [c_long; 2];
14+
safe static const_string: *const c_char;
715
}
816

917
fn main() {
10-
println!("{}", this_is_a_library_function())
18+
unsafe {
19+
println!(
20+
"{} {} {} {} {} {}",
21+
this_is_a_library_function(),
22+
global_variable,
23+
tls_variable,
24+
const_array[0],
25+
const_array[1],
26+
CStr::from_ptr(const_string).to_str().unwrap(),
27+
);
28+
}
1129
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
42
1+
42 3 33 795 906 sums of three cubes

tests/run-make/raw-dylib-elf/rmake.rs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,27 @@
1111
use run_make_support::{build_native_dynamic_lib, cwd, diff, run, rustc};
1212

1313
fn main() {
14-
// We compile the binary without having the library present.
14+
// We compile the binaries without having the library present with different relocation
15+
// models.
1516
// We also set the rpath to the current directory so we can pick up the library at runtime.
16-
rustc()
17-
.crate_type("bin")
18-
.input("main.rs")
19-
.arg(&format!("-Wl,-rpath={}", cwd().display()))
20-
.run();
17+
let relocation_models = ["static", "pic", "pie"];
18+
for relocation_model in relocation_models {
19+
rustc()
20+
.crate_type("bin")
21+
.input("main.rs")
22+
.arg(&format!("-Wl,-rpath={}", cwd().display()))
23+
.arg(&format!("-Crelocation-model={}", relocation_model))
24+
.output(&format!("main-{}", relocation_model))
25+
.run();
26+
}
2127

22-
// Now, *after* building the binary, we build the library...
28+
// Now, *after* building the binaries, we build the library...
2329
build_native_dynamic_lib("library");
2430

25-
// ... and run with this library, ensuring it was linked correctly at runtime.
26-
let output = run("main").stdout_utf8();
27-
28-
diff().expected_file("output.txt").actual_text("actual", output).run();
31+
for relocation_model in relocation_models {
32+
// ... and run with this library, ensuring it was linked correctly at runtime.
33+
// The output here should be the same regardless of the relocation model.
34+
let output = run(&format!("main-{}", relocation_model)).stdout_utf8();
35+
diff().expected_file("output.txt").actual_text("actual", output).run();
36+
}
2937
}

0 commit comments

Comments
 (0)