Skip to content

Commit

Permalink
Sync ar_archive_writer to LLVM 18.1.3
Browse files Browse the repository at this point in the history
From LLVM 15.0.0-rc3. This adds support for COFF archives containing
Arm64EC object files and has various fixes for AIX big archive files.
  • Loading branch information
bjorn3 committed Apr 16, 2024
1 parent 1dea922 commit 32ded4b
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 94 deletions.
15 changes: 12 additions & 3 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,11 @@ dependencies = [

[[package]]
name = "ar_archive_writer"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0c269894b6fe5e9d7ada0cf69b5bf847ff35bc25fc271f08e1d080fce80339a"
checksum = "f8412a2d690663356cba5a2532f3ed55d1e8090743bc6695b88403b27df67733"
dependencies = [
"object 0.32.2",
"object 0.35.0",
]

[[package]]
Expand Down Expand Up @@ -2658,6 +2658,15 @@ dependencies = [
"ruzstd 0.6.0",
]

[[package]]
name = "object"
version = "0.35.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e"
dependencies = [
"memchr",
]

[[package]]
name = "odht"
version = "0.3.1"
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_cranelift/src/archive.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use std::path::{Path, PathBuf};

use rustc_codegen_ssa::back::archive::{
get_native_object_symbols, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder,
ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
};
use rustc_session::Session;

pub(crate) struct ArArchiveBuilderBuilder;

impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
Box::new(ArArchiveBuilder::new(sess, get_native_object_symbols))
Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
}

fn create_dll_import_lib(
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_gcc/src/archive.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::path::{Path, PathBuf};

use rustc_codegen_ssa::back::archive::{
get_native_object_symbols, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder,
ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
};
use rustc_session::Session;

Expand All @@ -11,7 +11,7 @@ pub(crate) struct ArArchiveBuilderBuilder;

impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
Box::new(ArArchiveBuilder::new(sess, get_native_object_symbols))
Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
}

fn create_dll_import_lib(
Expand Down
109 changes: 67 additions & 42 deletions compiler/rustc_codegen_llvm/src/back/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use crate::errors::{
use crate::llvm::archive_ro::{ArchiveRO, Child};
use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
use rustc_codegen_ssa::back::archive::{
get_native_object_symbols, try_extract_macho_fat_archive, ArArchiveBuilder,
ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, UnknownArchiveKind,
try_extract_macho_fat_archive, ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder,
ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind, DEFAULT_OBJECT_READER,
};

use rustc_session::cstore::DllImport;
Expand Down Expand Up @@ -114,7 +114,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
if true {
Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() })
} else {
Box::new(ArArchiveBuilder::new(sess, get_llvm_object_symbols))
Box::new(ArArchiveBuilder::new(sess, &LLVM_OBJECT_READER))
}
}

Expand Down Expand Up @@ -296,59 +296,84 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {

// The object crate doesn't know how to get symbols for LLVM bitcode and COFF bigobj files.
// As such we need to use LLVM for them.

static LLVM_OBJECT_READER: ObjectReader = ObjectReader {
get_symbols: get_llvm_object_symbols,
is_64_bit_object_file: llvm_is_64_bit_object_file,
is_ec_object_file: llvm_is_ec_object_file,
get_xcoff_member_alignment: DEFAULT_OBJECT_READER.get_xcoff_member_alignment,
};

fn should_use_llvm_reader(buf: &[u8]) -> bool {
let is_bitcode = unsafe { llvm::LLVMRustIsBitcode(buf.as_ptr(), buf.len()) };

// COFF bigobj file, msvc LTO file or import library. See
// https://github.com/llvm/llvm-project/blob/453f27bc9/llvm/lib/BinaryFormat/Magic.cpp#L38-L51
let is_unsupported_windows_obj_file = buf.get(0..4) == Some(b"\0\0\xFF\xFF");

is_bitcode || is_unsupported_windows_obj_file
}

#[deny(unsafe_op_in_unsafe_fn)]
fn get_llvm_object_symbols(
buf: &[u8],
f: &mut dyn FnMut(&[u8]) -> io::Result<()>,
) -> io::Result<bool> {
let is_bitcode = unsafe { llvm::LLVMRustIsBitcode(buf.as_ptr(), buf.len()) };
if !should_use_llvm_reader(buf) {
return (DEFAULT_OBJECT_READER.get_symbols)(buf, f);
}

// COFF bigobj file, msvc LTO file or import library. See
// https://github.com/llvm/llvm-project/blob/453f27bc9/llvm/lib/BinaryFormat/Magic.cpp#L38-L51
let is_unsupported_windows_obj_file = buf.get(0..4) == Some(b"\0\0\xFF\xFF");
let mut state = Box::new(f);

if is_bitcode || is_unsupported_windows_obj_file {
let mut state = Box::new(f);

let err = unsafe {
llvm::LLVMRustGetSymbols(
buf.as_ptr(),
buf.len(),
std::ptr::addr_of_mut!(*state) as *mut c_void,
callback,
error_callback,
)
};
let err = unsafe {
llvm::LLVMRustGetSymbols(
buf.as_ptr(),
buf.len(),
std::ptr::addr_of_mut!(*state) as *mut c_void,
callback,
error_callback,
)
};

if err.is_null() {
return Ok(true);
} else {
return Err(unsafe { *Box::from_raw(err as *mut io::Error) });
}
if err.is_null() {
return Ok(true);
} else {
return Err(unsafe { *Box::from_raw(err as *mut io::Error) });
}

unsafe extern "C" fn callback(
state: *mut c_void,
symbol_name: *const c_char,
) -> *mut c_void {
let f = unsafe { &mut *(state as *mut &mut dyn FnMut(&[u8]) -> io::Result<()>) };
match f(unsafe { CStr::from_ptr(symbol_name) }.to_bytes()) {
Ok(()) => std::ptr::null_mut(),
Err(err) => Box::into_raw(Box::new(err)) as *mut c_void,
}
unsafe extern "C" fn callback(state: *mut c_void, symbol_name: *const c_char) -> *mut c_void {
let f = unsafe { &mut *(state as *mut &mut dyn FnMut(&[u8]) -> io::Result<()>) };
match f(unsafe { CStr::from_ptr(symbol_name) }.to_bytes()) {
Ok(()) => std::ptr::null_mut(),
Err(err) => Box::into_raw(Box::new(err)) as *mut c_void,
}
}

unsafe extern "C" fn error_callback(error: *const c_char) -> *mut c_void {
let error = unsafe { CStr::from_ptr(error) };
Box::into_raw(Box::new(io::Error::new(
io::ErrorKind::Other,
format!("LLVM error: {}", error.to_string_lossy()),
))) as *mut c_void
}
} else {
get_native_object_symbols(buf, f)
unsafe extern "C" fn error_callback(error: *const c_char) -> *mut c_void {
let error = unsafe { CStr::from_ptr(error) };
Box::into_raw(Box::new(io::Error::new(
io::ErrorKind::Other,
format!("LLVM error: {}", error.to_string_lossy()),
))) as *mut c_void
}
}

fn llvm_is_64_bit_object_file(buf: &[u8]) -> bool {
if !should_use_llvm_reader(buf) {
return (DEFAULT_OBJECT_READER.is_64_bit_object_file)(buf);
}

unsafe { llvm::LLVMRustIs64BitSymbolicFile(buf.as_ptr(), buf.len()) }
}

fn llvm_is_ec_object_file(buf: &[u8]) -> bool {
if !should_use_llvm_reader(buf) {
return (DEFAULT_OBJECT_READER.is_ec_object_file)(buf);
}

unsafe { llvm::LLVMRustIsECObject(buf.as_ptr(), buf.len()) }
}

impl<'a> LlvmArchiveBuilder<'a> {
fn build_with_llvm(&mut self, output: &Path) -> io::Result<bool> {
let kind = &*self.sess.target.archive_format;
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2427,4 +2427,8 @@ extern "C" {
callback: GetSymbolsCallback,
error_callback: GetSymbolsErrorCallback,
) -> *mut c_void;

pub fn LLVMRustIs64BitSymbolicFile(buf_ptr: *const u8, buf_len: usize) -> bool;

pub fn LLVMRustIsECObject(buf_ptr: *const u8, buf_len: usize) -> bool;
}
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ edition = "2021"

[dependencies]
# tidy-alphabetical-start
ar_archive_writer = "0.2.0"
ar_archive_writer = "0.3.0"
bitflags = "2.4.1"
cc = "1.0.90"
itertools = "0.12"
Expand Down
25 changes: 12 additions & 13 deletions compiler/rustc_codegen_ssa/src/back/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use rustc_span::symbol::Symbol;

use super::metadata::search_for_section;

pub use ar_archive_writer::get_native_object_symbols;
use ar_archive_writer::{write_archive_to_stream, ArchiveKind, NewArchiveMember};
pub use ar_archive_writer::{ObjectReader, DEFAULT_OBJECT_READER};
use object::read::archive::ArchiveFile;
use object::read::macho::FatArch;
use tempfile::Builder as TempFileBuilder;
Expand Down Expand Up @@ -89,8 +89,7 @@ pub trait ArchiveBuilder {
#[must_use = "must call build() to finish building the archive"]
pub struct ArArchiveBuilder<'a> {
sess: &'a Session,
get_object_symbols:
fn(buf: &[u8], f: &mut dyn FnMut(&[u8]) -> io::Result<()>) -> io::Result<bool>,
object_reader: &'static ObjectReader,

src_archives: Vec<(PathBuf, Mmap)>,
// Don't use an `HashMap` here, as the order is important. `lib.rmeta` needs
Expand All @@ -105,14 +104,8 @@ enum ArchiveEntry {
}

impl<'a> ArArchiveBuilder<'a> {
pub fn new(
sess: &'a Session,
get_object_symbols: fn(
buf: &[u8],
f: &mut dyn FnMut(&[u8]) -> io::Result<()>,
) -> io::Result<bool>,
) -> ArArchiveBuilder<'a> {
ArArchiveBuilder { sess, get_object_symbols, src_archives: vec![], entries: vec![] }
pub fn new(sess: &'a Session, object_reader: &'static ObjectReader) -> ArArchiveBuilder<'a> {
ArArchiveBuilder { sess, object_reader, src_archives: vec![], entries: vec![] }
}
}

Expand Down Expand Up @@ -267,7 +260,7 @@ impl<'a> ArArchiveBuilder<'a> {

entries.push(NewArchiveMember {
buf: data,
get_symbols: self.get_object_symbols,
object_reader: self.object_reader,
member_name: String::from_utf8(entry_name).unwrap(),
mtime: 0,
uid: 0,
Expand All @@ -285,7 +278,13 @@ impl<'a> ArArchiveBuilder<'a> {
.tempfile_in(output.parent().unwrap_or_else(|| Path::new("")))
.map_err(|err| io_error_context("couldn't create a temp file", err))?;

write_archive_to_stream(archive_tmpfile.as_file_mut(), &entries, archive_kind, false)?;
write_archive_to_stream(
archive_tmpfile.as_file_mut(),
&entries,
archive_kind,
false,
self.sess.target.arch == "arm64ec",
)?;

let any_entries = !entries.is_empty();
drop(entries);
Expand Down
Loading

0 comments on commit 32ded4b

Please sign in to comment.