Auto merge of #128936 - bjorn3:fix_thin_archive_reading, r=jieyouxu

Support reading thin archives in ArArchiveBuilder

And switch to using ArArchiveBuilder with the LLVM backend too now that all regressions are fixed.

Fixes https://github.com/rust-lang/rust/issues/107407
Fixes https://github.com/rust-lang/rust/issues/107162
https://github.com/rust-lang/rust/issues/107495 has been fixed in a previous PR already.
This commit is contained in:
bors 2024-08-15 14:13:52 +00:00
commit d2b5aa6552
8 changed files with 63 additions and 38 deletions

View File

@ -106,9 +106,11 @@ pub struct LlvmArchiveBuilderBuilder;
impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> { fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
// FIXME use ArArchiveBuilder on most targets again once reading thin archives is // Keeping LlvmArchiveBuilder around in case of a regression caused by using
// implemented // ArArchiveBuilder.
if true { // FIXME(#128955) remove a couple of months after #128936 gets merged in case
// no regression is found.
if false {
Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() }) Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() })
} else { } else {
Box::new(ArArchiveBuilder::new(sess, &LLVM_OBJECT_READER)) Box::new(ArArchiveBuilder::new(sess, &LLVM_OBJECT_READER))
@ -198,25 +200,11 @@ static LLVM_OBJECT_READER: ObjectReader = ObjectReader {
get_xcoff_member_alignment: DEFAULT_OBJECT_READER.get_xcoff_member_alignment, 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)] #[deny(unsafe_op_in_unsafe_fn)]
fn get_llvm_object_symbols( fn get_llvm_object_symbols(
buf: &[u8], buf: &[u8],
f: &mut dyn FnMut(&[u8]) -> io::Result<()>, f: &mut dyn FnMut(&[u8]) -> io::Result<()>,
) -> io::Result<bool> { ) -> io::Result<bool> {
if !should_use_llvm_reader(buf) {
return (DEFAULT_OBJECT_READER.get_symbols)(buf, f);
}
let mut state = Box::new(f); let mut state = Box::new(f);
let err = unsafe { let err = unsafe {
@ -253,18 +241,10 @@ fn get_llvm_object_symbols(
} }
fn llvm_is_64_bit_object_file(buf: &[u8]) -> bool { 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()) } unsafe { llvm::LLVMRustIs64BitSymbolicFile(buf.as_ptr(), buf.len()) }
} }
fn llvm_is_ec_object_file(buf: &[u8]) -> bool { 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()) } unsafe { llvm::LLVMRustIsECObject(buf.as_ptr(), buf.len()) }
} }

View File

@ -307,12 +307,17 @@ impl<'a> ArchiveBuilder for ArArchiveBuilder<'a> {
let file_name = String::from_utf8(entry.name().to_vec()) let file_name = String::from_utf8(entry.name().to_vec())
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
if !skip(&file_name) { if !skip(&file_name) {
if entry.is_thin() {
let member_path = archive_path.parent().unwrap().join(Path::new(&file_name));
self.entries.push((file_name.into_bytes(), ArchiveEntry::File(member_path)));
} else {
self.entries.push(( self.entries.push((
file_name.into_bytes(), file_name.into_bytes(),
ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() }, ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() },
)); ));
} }
} }
}
self.src_archives.push((archive_path, archive_map)); self.src_archives.push((archive_path, archive_map));
Ok(()) Ok(())

View File

@ -77,22 +77,18 @@ LLVMRustGetSymbols(char *BufPtr, size_t BufLen, void *State,
Expected<std::unique_ptr<object::SymbolicFile>> ObjOrErr = Expected<std::unique_ptr<object::SymbolicFile>> ObjOrErr =
getSymbolicFile(Buf->getMemBufferRef(), Context); getSymbolicFile(Buf->getMemBufferRef(), Context);
if (!ObjOrErr) { if (!ObjOrErr) {
Error E = ObjOrErr.takeError(); return ErrorCallback(toString(ObjOrErr.takeError()).c_str());
SmallString<0> ErrorBuf;
auto Error = raw_svector_ostream(ErrorBuf);
Error << E << '\0';
return ErrorCallback(Error.str().data());
} }
std::unique_ptr<object::SymbolicFile> Obj = std::move(*ObjOrErr); std::unique_ptr<object::SymbolicFile> Obj = std::move(*ObjOrErr);
if (Obj == nullptr) {
return 0;
}
for (const object::BasicSymbolRef &S : Obj->symbols()) { for (const object::BasicSymbolRef &S : Obj->symbols()) {
if (!isArchiveSymbol(S)) if (!isArchiveSymbol(S))
continue; continue;
if (Error E = S.printName(SymName)) { if (Error E = S.printName(SymName)) {
SmallString<0> ErrorBuf; return ErrorCallback(toString(std::move(E)).c_str());
auto Error = raw_svector_ostream(ErrorBuf);
Error << E << '\0';
return ErrorCallback(Error.str().data());
} }
SymName << '\0'; SymName << '\0';
if (void *E = Callback(State, SymNameBuf.str().data())) { if (void *E = Callback(State, SymNameBuf.str().data())) {

View File

@ -285,6 +285,12 @@ impl LlvmAr {
self self
} }
/// Like `obj_to_ar` except creating a thin archive.
pub fn obj_to_thin_ar(&mut self) -> &mut Self {
self.cmd.arg("rcus").arg("--thin");
self
}
/// Extract archive members back to files. /// Extract archive members back to files.
pub fn extract(&mut self) -> &mut Self { pub fn extract(&mut self) -> &mut Self {
self.cmd.arg("x"); self.cmd.arg("x");

View File

@ -0,0 +1,5 @@
fn main() {
unsafe {
rust_lib::simple_fn();
}
}

View File

@ -0,0 +1,23 @@
// Regression test for https://github.com/rust-lang/rust/issues/107407 which
// checks that rustc can read thin archive. Before the object crate added thin
// archive support rustc would add emit object files to the staticlib and after
// the object crate added thin archive support it would previously crash the
// compiler due to a missing special case for thin archive members.
use run_make_support::{llvm_ar, path, rfs, rust_lib_name, rustc, static_lib_name};
fn main() {
rfs::create_dir("archive");
// Build a thin archive
rustc().input("simple_obj.rs").emit("obj").output("archive/simple_obj.o").run();
llvm_ar()
.obj_to_thin_ar()
.output_input(path("archive").join(static_lib_name("thin_archive")), "archive/simple_obj.o")
.run();
// Build an rlib which includes the members of this thin archive
rustc().input("rust_lib.rs").library_search_path("archive").run();
// Build a binary which requires a symbol from the thin archive
rustc().input("bin.rs").extern_("rust_lib", rust_lib_name("rust_lib")).run();
}

View File

@ -0,0 +1,6 @@
#![crate_type = "rlib"]
#[link(name = "thin_archive", kind = "static")]
extern "C" {
pub fn simple_fn();
}

View File

@ -0,0 +1,4 @@
#![crate_type = "staticlib"]
#[no_mangle]
extern "C" fn simple_fn() {}