
This commit updates how rustc compiler metadata is stored in rlibs. Previously metadata was stored as a raw file that has the same format as `--emit metadata`. After this commit, however, the metadata is encoded into a small object file which has one section which is the contents of the metadata. The motivation for this commit is to fix a common case where #83730 arises. The problem is that when rustc crates a `dylib` crate type it needs to include entire rlib files into the dylib, so it passes `--whole-archive` (or the equivalent) to the linker. The problem with this, though, is that the linker will attempt to read all files in the archive. If the metadata file were left as-is (today) then the linker would generate an error saying it can't read the file. The previous solution was to alter the rlib just before linking, creating a new archive in a temporary directory which has the metadata file removed. This problem from before this commit is now removed if the metadata file is stored in an object file that the linker can read. The only caveat we have to take care of is to ensure that the linker never actually includes the contents of the object file into the final output. We apply similar tricks as the `.llvmbc` bytecode sections to do this. This involved changing the metadata loading code a bit, namely updating some of the LLVM C APIs used to use non-deprecated ones and fiddling with the lifetimes a bit to get everything to work out. Otherwise though this isn't intended to be a functional change really, only that metadata is stored differently in archives now. This should end up fixing #83730 because by default dylibs will no longer have their rlib dependencies "altered" meaning that split-debuginfo will continue to have valid paths pointing at the original rlibs. (note that we still "alter" rlibs if LTO is enabled to remove Rust object files and we also "alter" for the #[link(cfg)] feature, but that's rarely used). Closes #83730
283 lines
7.7 KiB
Rust
283 lines
7.7 KiB
Rust
#![allow(non_snake_case)]
|
|
|
|
pub use self::AtomicRmwBinOp::*;
|
|
pub use self::CallConv::*;
|
|
pub use self::CodeGenOptSize::*;
|
|
pub use self::IntPredicate::*;
|
|
pub use self::Linkage::*;
|
|
pub use self::MetadataType::*;
|
|
pub use self::RealPredicate::*;
|
|
|
|
use libc::c_uint;
|
|
use rustc_data_structures::small_c_str::SmallCStr;
|
|
use rustc_llvm::RustString;
|
|
use std::cell::RefCell;
|
|
use std::ffi::{CStr, CString};
|
|
use std::str::FromStr;
|
|
use std::string::FromUtf8Error;
|
|
|
|
pub mod archive_ro;
|
|
pub mod diagnostic;
|
|
mod ffi;
|
|
|
|
pub use self::ffi::*;
|
|
|
|
impl LLVMRustResult {
|
|
pub fn into_result(self) -> Result<(), ()> {
|
|
match self {
|
|
LLVMRustResult::Success => Ok(()),
|
|
LLVMRustResult::Failure => Err(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn AddFunctionAttrStringValue(llfn: &'a Value, idx: AttributePlace, attr: &CStr, value: &CStr) {
|
|
unsafe {
|
|
LLVMRustAddFunctionAttrStringValue(llfn, idx.as_uint(), attr.as_ptr(), value.as_ptr())
|
|
}
|
|
}
|
|
|
|
pub fn AddFunctionAttrString(llfn: &'a Value, idx: AttributePlace, attr: &CStr) {
|
|
unsafe {
|
|
LLVMRustAddFunctionAttrStringValue(llfn, idx.as_uint(), attr.as_ptr(), std::ptr::null())
|
|
}
|
|
}
|
|
|
|
pub fn AddCallSiteAttrString(callsite: &Value, idx: AttributePlace, attr: &CStr) {
|
|
unsafe { LLVMRustAddCallSiteAttrString(callsite, idx.as_uint(), attr.as_ptr()) }
|
|
}
|
|
|
|
#[derive(Copy, Clone)]
|
|
pub enum AttributePlace {
|
|
ReturnValue,
|
|
Argument(u32),
|
|
Function,
|
|
}
|
|
|
|
impl AttributePlace {
|
|
pub fn as_uint(self) -> c_uint {
|
|
match self {
|
|
AttributePlace::ReturnValue => 0,
|
|
AttributePlace::Argument(i) => 1 + i,
|
|
AttributePlace::Function => !0,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, PartialEq)]
|
|
#[repr(C)]
|
|
pub enum CodeGenOptSize {
|
|
CodeGenOptSizeNone = 0,
|
|
CodeGenOptSizeDefault = 1,
|
|
CodeGenOptSizeAggressive = 2,
|
|
}
|
|
|
|
impl FromStr for ArchiveKind {
|
|
type Err = ();
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
match s {
|
|
"gnu" => Ok(ArchiveKind::K_GNU),
|
|
"bsd" => Ok(ArchiveKind::K_BSD),
|
|
"darwin" => Ok(ArchiveKind::K_DARWIN),
|
|
"coff" => Ok(ArchiveKind::K_COFF),
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn SetInstructionCallConv(instr: &'a Value, cc: CallConv) {
|
|
unsafe {
|
|
LLVMSetInstructionCallConv(instr, cc as c_uint);
|
|
}
|
|
}
|
|
pub fn SetFunctionCallConv(fn_: &'a Value, cc: CallConv) {
|
|
unsafe {
|
|
LLVMSetFunctionCallConv(fn_, cc as c_uint);
|
|
}
|
|
}
|
|
|
|
// Externally visible symbols that might appear in multiple codegen units need to appear in
|
|
// their own comdat section so that the duplicates can be discarded at link time. This can for
|
|
// example happen for generics when using multiple codegen units. This function simply uses the
|
|
// value's name as the comdat value to make sure that it is in a 1-to-1 relationship to the
|
|
// function.
|
|
// For more details on COMDAT sections see e.g., http://www.airs.com/blog/archives/52
|
|
pub fn SetUniqueComdat(llmod: &Module, val: &'a Value) {
|
|
unsafe {
|
|
let name = get_value_name(val);
|
|
LLVMRustSetComdat(llmod, val, name.as_ptr().cast(), name.len());
|
|
}
|
|
}
|
|
|
|
pub fn UnsetComdat(val: &'a Value) {
|
|
unsafe {
|
|
LLVMRustUnsetComdat(val);
|
|
}
|
|
}
|
|
|
|
pub fn SetUnnamedAddress(global: &'a Value, unnamed: UnnamedAddr) {
|
|
unsafe {
|
|
LLVMSetUnnamedAddress(global, unnamed);
|
|
}
|
|
}
|
|
|
|
pub fn set_thread_local_mode(global: &'a Value, mode: ThreadLocalMode) {
|
|
unsafe {
|
|
LLVMSetThreadLocalMode(global, mode);
|
|
}
|
|
}
|
|
|
|
impl Attribute {
|
|
pub fn apply_llfn(&self, idx: AttributePlace, llfn: &Value) {
|
|
unsafe { LLVMRustAddFunctionAttribute(llfn, idx.as_uint(), *self) }
|
|
}
|
|
|
|
pub fn apply_callsite(&self, idx: AttributePlace, callsite: &Value) {
|
|
unsafe { LLVMRustAddCallSiteAttribute(callsite, idx.as_uint(), *self) }
|
|
}
|
|
|
|
pub fn unapply_llfn(&self, idx: AttributePlace, llfn: &Value) {
|
|
unsafe { LLVMRustRemoveFunctionAttributes(llfn, idx.as_uint(), *self) }
|
|
}
|
|
|
|
pub fn toggle_llfn(&self, idx: AttributePlace, llfn: &Value, set: bool) {
|
|
if set {
|
|
self.apply_llfn(idx, llfn);
|
|
} else {
|
|
self.unapply_llfn(idx, llfn);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn set_section(llglobal: &Value, section_name: &str) {
|
|
let section_name_cstr = CString::new(section_name).expect("unexpected CString error");
|
|
unsafe {
|
|
LLVMSetSection(llglobal, section_name_cstr.as_ptr());
|
|
}
|
|
}
|
|
|
|
pub fn add_global<'a>(llmod: &'a Module, ty: &'a Type, name: &str) -> &'a Value {
|
|
let name_cstr = CString::new(name).expect("unexpected CString error");
|
|
unsafe { LLVMAddGlobal(llmod, ty, name_cstr.as_ptr()) }
|
|
}
|
|
|
|
pub fn set_initializer(llglobal: &Value, constant_val: &Value) {
|
|
unsafe {
|
|
LLVMSetInitializer(llglobal, constant_val);
|
|
}
|
|
}
|
|
|
|
pub fn set_global_constant(llglobal: &Value, is_constant: bool) {
|
|
unsafe {
|
|
LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False });
|
|
}
|
|
}
|
|
|
|
pub fn set_linkage(llglobal: &Value, linkage: Linkage) {
|
|
unsafe {
|
|
LLVMRustSetLinkage(llglobal, linkage);
|
|
}
|
|
}
|
|
|
|
pub fn set_visibility(llglobal: &Value, visibility: Visibility) {
|
|
unsafe {
|
|
LLVMRustSetVisibility(llglobal, visibility);
|
|
}
|
|
}
|
|
|
|
pub fn set_alignment(llglobal: &Value, bytes: usize) {
|
|
unsafe {
|
|
ffi::LLVMSetAlignment(llglobal, bytes as c_uint);
|
|
}
|
|
}
|
|
|
|
pub fn set_comdat(llmod: &Module, llglobal: &Value, name: &str) {
|
|
unsafe {
|
|
LLVMRustSetComdat(llmod, llglobal, name.as_ptr().cast(), name.len());
|
|
}
|
|
}
|
|
|
|
/// Safe wrapper around `LLVMGetParam`, because segfaults are no fun.
|
|
pub fn get_param(llfn: &Value, index: c_uint) -> &Value {
|
|
unsafe {
|
|
assert!(
|
|
index < LLVMCountParams(llfn),
|
|
"out of bounds argument access: {} out of {} arguments",
|
|
index,
|
|
LLVMCountParams(llfn)
|
|
);
|
|
LLVMGetParam(llfn, index)
|
|
}
|
|
}
|
|
|
|
/// Safe wrapper for `LLVMGetValueName2` into a byte slice
|
|
pub fn get_value_name(value: &Value) -> &[u8] {
|
|
unsafe {
|
|
let mut len = 0;
|
|
let data = LLVMGetValueName2(value, &mut len);
|
|
std::slice::from_raw_parts(data.cast(), len)
|
|
}
|
|
}
|
|
|
|
/// Safe wrapper for `LLVMSetValueName2` from a byte slice
|
|
pub fn set_value_name(value: &Value, name: &[u8]) {
|
|
unsafe {
|
|
let data = name.as_ptr().cast();
|
|
LLVMSetValueName2(value, data, name.len());
|
|
}
|
|
}
|
|
|
|
pub fn build_string(f: impl FnOnce(&RustString)) -> Result<String, FromUtf8Error> {
|
|
let sr = RustString { bytes: RefCell::new(Vec::new()) };
|
|
f(&sr);
|
|
String::from_utf8(sr.bytes.into_inner())
|
|
}
|
|
|
|
pub fn build_byte_buffer(f: impl FnOnce(&RustString)) -> Vec<u8> {
|
|
let sr = RustString { bytes: RefCell::new(Vec::new()) };
|
|
f(&sr);
|
|
sr.bytes.into_inner()
|
|
}
|
|
|
|
pub fn twine_to_string(tr: &Twine) -> String {
|
|
unsafe {
|
|
build_string(|s| LLVMRustWriteTwineToString(tr, s)).expect("got a non-UTF8 Twine from LLVM")
|
|
}
|
|
}
|
|
|
|
pub fn last_error() -> Option<String> {
|
|
unsafe {
|
|
let cstr = LLVMRustGetLastError();
|
|
if cstr.is_null() {
|
|
None
|
|
} else {
|
|
let err = CStr::from_ptr(cstr).to_bytes();
|
|
let err = String::from_utf8_lossy(err).to_string();
|
|
libc::free(cstr as *mut _);
|
|
Some(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct OperandBundleDef<'a> {
|
|
pub raw: &'a mut ffi::OperandBundleDef<'a>,
|
|
}
|
|
|
|
impl OperandBundleDef<'a> {
|
|
pub fn new(name: &str, vals: &[&'a Value]) -> Self {
|
|
let name = SmallCStr::new(name);
|
|
let def = unsafe {
|
|
LLVMRustBuildOperandBundleDef(name.as_ptr(), vals.as_ptr(), vals.len() as c_uint)
|
|
};
|
|
OperandBundleDef { raw: def }
|
|
}
|
|
}
|
|
|
|
impl Drop for OperandBundleDef<'a> {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
LLVMRustFreeOperandBundleDef(&mut *(self.raw as *mut _));
|
|
}
|
|
}
|
|
}
|