about summary refs log tree commit diff
path: root/src/librustc_codegen_llvm
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustc_codegen_llvm')
-rw-r--r--src/librustc_codegen_llvm/back/archive.rs6
-rw-r--r--src/librustc_codegen_llvm/back/bytecode.rs141
-rw-r--r--src/librustc_codegen_llvm/back/lto.rs48
-rw-r--r--src/librustc_codegen_llvm/back/write.rs66
-rw-r--r--src/librustc_codegen_llvm/lib.rs1
-rw-r--r--src/librustc_codegen_llvm/llvm/ffi.rs5
6 files changed, 90 insertions, 177 deletions
diff --git a/src/librustc_codegen_llvm/back/archive.rs b/src/librustc_codegen_llvm/back/archive.rs
index f1fe40d919e..a115a1e9516 100644
--- a/src/librustc_codegen_llvm/back/archive.rs
+++ b/src/librustc_codegen_llvm/back/archive.rs
@@ -10,7 +10,7 @@ use std::str;
 use crate::llvm::archive_ro::{ArchiveRO, Child};
 use crate::llvm::{self, ArchiveKind};
 use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder};
-use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME, RLIB_BYTECODE_EXTENSION};
+use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME};
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
 
@@ -129,8 +129,8 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
         let obj_start = name.to_owned();
 
         self.add_archive(rlib, move |fname: &str| {
-            // Ignore bytecode/metadata files, no matter the name.
-            if fname.ends_with(RLIB_BYTECODE_EXTENSION) || fname == METADATA_FILENAME {
+            // Ignore metadata files, no matter the name.
+            if fname == METADATA_FILENAME {
                 return true;
             }
 
diff --git a/src/librustc_codegen_llvm/back/bytecode.rs b/src/librustc_codegen_llvm/back/bytecode.rs
deleted file mode 100644
index 0c8ce39132a..00000000000
--- a/src/librustc_codegen_llvm/back/bytecode.rs
+++ /dev/null
@@ -1,141 +0,0 @@
-//! Management of the encoding of LLVM bytecode into rlibs
-//!
-//! This module contains the management of encoding LLVM bytecode into rlibs,
-//! primarily for the usage in LTO situations. Currently the compiler will
-//! unconditionally encode LLVM-IR into rlibs regardless of what's happening
-//! elsewhere, so we currently compress the bytecode via deflate to avoid taking
-//! up too much space on disk.
-//!
-//! After compressing the bytecode we then have the rest of the format to
-//! basically deal with various bugs in various archive implementations. The
-//! format currently is:
-//!
-//!     RLIB LLVM-BYTECODE OBJECT LAYOUT
-//!     Version 2
-//!     Bytes    Data
-//!     0..10    "RUST_OBJECT" encoded in ASCII
-//!     11..14   format version as little-endian u32
-//!     15..19   the length of the module identifier string
-//!     20..n    the module identifier string
-//!     n..n+8   size in bytes of deflate compressed LLVM bitcode as
-//!              little-endian u64
-//!     n+9..    compressed LLVM bitcode
-//!     ?        maybe a byte to make this whole thing even length
-
-use std::io::{Read, Write};
-use std::ptr;
-use std::str;
-
-use flate2::read::DeflateDecoder;
-use flate2::write::DeflateEncoder;
-use flate2::Compression;
-
-// This is the "magic number" expected at the beginning of a LLVM bytecode
-// object in an rlib.
-pub const RLIB_BYTECODE_OBJECT_MAGIC: &[u8] = b"RUST_OBJECT";
-
-// The version number this compiler will write to bytecode objects in rlibs
-pub const RLIB_BYTECODE_OBJECT_VERSION: u8 = 2;
-
-pub fn encode(identifier: &str, bytecode: &[u8]) -> Vec<u8> {
-    let mut encoded = Vec::new();
-
-    // Start off with the magic string
-    encoded.extend_from_slice(RLIB_BYTECODE_OBJECT_MAGIC);
-
-    // Next up is the version
-    encoded.extend_from_slice(&[RLIB_BYTECODE_OBJECT_VERSION, 0, 0, 0]);
-
-    // Next is the LLVM module identifier length + contents
-    let identifier_len = identifier.len();
-    encoded.extend_from_slice(&[
-        (identifier_len >> 0) as u8,
-        (identifier_len >> 8) as u8,
-        (identifier_len >> 16) as u8,
-        (identifier_len >> 24) as u8,
-    ]);
-    encoded.extend_from_slice(identifier.as_bytes());
-
-    // Next is the LLVM module deflate compressed, prefixed with its length. We
-    // don't know its length yet, so fill in 0s
-    let deflated_size_pos = encoded.len();
-    encoded.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]);
-
-    let before = encoded.len();
-    DeflateEncoder::new(&mut encoded, Compression::fast()).write_all(bytecode).unwrap();
-    let after = encoded.len();
-
-    // Fill in the length we reserved space for before
-    let bytecode_len = (after - before) as u64;
-    encoded[deflated_size_pos + 0] = (bytecode_len >> 0) as u8;
-    encoded[deflated_size_pos + 1] = (bytecode_len >> 8) as u8;
-    encoded[deflated_size_pos + 2] = (bytecode_len >> 16) as u8;
-    encoded[deflated_size_pos + 3] = (bytecode_len >> 24) as u8;
-    encoded[deflated_size_pos + 4] = (bytecode_len >> 32) as u8;
-    encoded[deflated_size_pos + 5] = (bytecode_len >> 40) as u8;
-    encoded[deflated_size_pos + 6] = (bytecode_len >> 48) as u8;
-    encoded[deflated_size_pos + 7] = (bytecode_len >> 56) as u8;
-
-    // If the number of bytes written to the object so far is odd, add a
-    // padding byte to make it even. This works around a crash bug in LLDB
-    // (see issue #15950)
-    if encoded.len() % 2 == 1 {
-        encoded.push(0);
-    }
-
-    encoded
-}
-
-pub struct DecodedBytecode<'a> {
-    identifier: &'a str,
-    encoded_bytecode: &'a [u8],
-}
-
-impl<'a> DecodedBytecode<'a> {
-    pub fn new(data: &'a [u8]) -> Result<DecodedBytecode<'a>, &'static str> {
-        if !data.starts_with(RLIB_BYTECODE_OBJECT_MAGIC) {
-            return Err("magic bytecode prefix not found");
-        }
-        let data = &data[RLIB_BYTECODE_OBJECT_MAGIC.len()..];
-        if !data.starts_with(&[RLIB_BYTECODE_OBJECT_VERSION, 0, 0, 0]) {
-            return Err("wrong version prefix found in bytecode");
-        }
-        let data = &data[4..];
-        if data.len() < 4 {
-            return Err("bytecode corrupted");
-        }
-        let identifier_len =
-            unsafe { u32::from_le(ptr::read_unaligned(data.as_ptr() as *const u32)) as usize };
-        let data = &data[4..];
-        if data.len() < identifier_len {
-            return Err("bytecode corrupted");
-        }
-        let identifier = match str::from_utf8(&data[..identifier_len]) {
-            Ok(s) => s,
-            Err(_) => return Err("bytecode corrupted"),
-        };
-        let data = &data[identifier_len..];
-        if data.len() < 8 {
-            return Err("bytecode corrupted");
-        }
-        let bytecode_len =
-            unsafe { u64::from_le(ptr::read_unaligned(data.as_ptr() as *const u64)) as usize };
-        let data = &data[8..];
-        if data.len() < bytecode_len {
-            return Err("bytecode corrupted");
-        }
-        let encoded_bytecode = &data[..bytecode_len];
-
-        Ok(DecodedBytecode { identifier, encoded_bytecode })
-    }
-
-    pub fn bytecode(&self) -> Vec<u8> {
-        let mut data = Vec::new();
-        DeflateDecoder::new(self.encoded_bytecode).read_to_end(&mut data).unwrap();
-        data
-    }
-
-    pub fn identifier(&self) -> &'a str {
-        self.identifier
-    }
-}
diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs
index 7292492a0c0..e65bdbe171b 100644
--- a/src/librustc_codegen_llvm/back/lto.rs
+++ b/src/librustc_codegen_llvm/back/lto.rs
@@ -1,4 +1,3 @@
-use crate::back::bytecode::DecodedBytecode;
 use crate::back::write::{
     self, save_temp_bitcode, to_llvm_opt_settings, with_llvm_pmb, DiagnosticHandlers,
 };
@@ -10,7 +9,7 @@ use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModul
 use rustc_codegen_ssa::back::symbol_export;
 use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig};
 use rustc_codegen_ssa::traits::*;
-use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, RLIB_BYTECODE_EXTENSION};
+use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{FatalError, Handler};
 use rustc_hir::def_id::LOCAL_CRATE;
@@ -111,22 +110,19 @@ fn prepare_lto(
             }
 
             let archive = ArchiveRO::open(&path).expect("wanted an rlib");
-            let bytecodes = archive
+            let obj_files = archive
                 .iter()
                 .filter_map(|child| child.ok().and_then(|c| c.name().map(|name| (name, c))))
-                .filter(|&(name, _)| name.ends_with(RLIB_BYTECODE_EXTENSION));
-            for (name, data) in bytecodes {
-                let _timer =
-                    cgcx.prof.generic_activity_with_arg("LLVM_lto_load_upstream_bitcode", name);
-                info!("adding bytecode {}", name);
-                let bc_encoded = data.data();
-
-                let (bc, id) = match DecodedBytecode::new(bc_encoded) {
-                    Ok(b) => Ok((b.bytecode(), b.identifier().to_string())),
-                    Err(e) => Err(diag_handler.fatal(&e)),
-                }?;
-                let bc = SerializedModule::FromRlib(bc);
-                upstream_modules.push((bc, CString::new(id).unwrap()));
+                .filter(|&(name, _)| looks_like_rust_object_file(name));
+            for (name, child) in obj_files {
+                info!("adding bitcode from {}", name);
+                match get_bitcode_slice_from_object_data(child.data()) {
+                    Ok(data) => {
+                        let module = SerializedModule::FromRlib(data.to_vec());
+                        upstream_modules.push((module, CString::new(name).unwrap()));
+                    }
+                    Err(msg) => return Err(diag_handler.fatal(&msg)),
+                }
             }
         }
     }
@@ -134,6 +130,26 @@ fn prepare_lto(
     Ok((symbol_white_list, upstream_modules))
 }
 
+fn get_bitcode_slice_from_object_data(obj: &[u8]) -> Result<&[u8], String> {
+    let mut len = 0;
+    let data =
+        unsafe { llvm::LLVMRustGetBitcodeSliceFromObjectData(obj.as_ptr(), obj.len(), &mut len) };
+    if !data.is_null() {
+        assert!(len != 0);
+        let bc = unsafe { slice::from_raw_parts(data, len) };
+
+        // `bc` must be a sub-slice of `obj`.
+        assert!(obj.as_ptr() <= bc.as_ptr());
+        assert!(bc[bc.len()..bc.len()].as_ptr() <= obj[obj.len()..obj.len()].as_ptr());
+
+        Ok(bc)
+    } else {
+        assert!(len == 0);
+        let msg = llvm::last_error().unwrap_or_else(|| "unknown LLVM error".to_string());
+        Err(format!("failed to get bitcode from object file for LTO ({})", msg))
+    }
+}
+
 /// Performs fat LTO by merging all modules into a single one and returning it
 /// for further optimization.
 pub(crate) fn run_fat(
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index b57ad102d63..5f4c122f02c 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -1,5 +1,4 @@
 use crate::attributes;
-use crate::back::bytecode;
 use crate::back::lto::ThinBuffer;
 use crate::back::profiling::{
     selfprofile_after_pass_callback, selfprofile_before_pass_callback, LlvmSelfProfiler,
@@ -16,7 +15,7 @@ use crate::ModuleLlvm;
 use log::debug;
 use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig};
 use rustc_codegen_ssa::traits::*;
-use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, RLIB_BYTECODE_EXTENSION};
+use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_errors::{FatalError, Handler};
 use rustc_fs_util::{link_or_copy, path_to_c_string};
@@ -669,19 +668,6 @@ pub(crate) unsafe fn codegen(
                 );
                 embed_bitcode(cgcx, llcx, llmod, Some(data));
             }
-
-            if config.emit_bc_compressed {
-                let _timer = cgcx.prof.generic_activity_with_arg(
-                    "LLVM_module_codegen_emit_compressed_bitcode",
-                    &module.name[..],
-                );
-                let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION);
-                let data = bytecode::encode(&module.name, data);
-                if let Err(e) = fs::write(&dst, data) {
-                    let msg = format!("failed to write bytecode to {}: {}", dst.display(), e);
-                    diag_handler.err(&msg);
-                }
-            }
         } else if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Marker) {
             embed_bitcode(cgcx, llcx, llmod, None);
         }
@@ -792,7 +778,6 @@ pub(crate) unsafe fn codegen(
     Ok(module.into_compiled_module(
         config.emit_obj != EmitObj::None,
         config.emit_bc,
-        config.emit_bc_compressed,
         &cgcx.output_filenames,
     ))
 }
@@ -847,6 +832,55 @@ unsafe fn embed_bitcode(
     let section = if is_apple { "__LLVM,__cmdline\0" } else { ".llvmcmd\0" };
     llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
     llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
+
+    // We're adding custom sections to the output object file, but we definitely
+    // do not want these custom sections to make their way into the final linked
+    // executable. The purpose of these custom sections is for tooling
+    // surrounding object files to work with the LLVM IR, if necessary. For
+    // example rustc's own LTO will look for LLVM IR inside of the object file
+    // in these sections by default.
+    //
+    // To handle this is a bit different depending on the object file format
+    // used by the backend, broken down into a few different categories:
+    //
+    // * Mach-O - this is for macOS. Inspecting the source code for the native
+    //   linker here shows that the `.llvmbc` and `.llvmcmd` sections are
+    //   automatically skipped by the linker. In that case there's nothing extra
+    //   that we need to do here.
+    //
+    // * Wasm - the native LLD linker is hard-coded to skip `.llvmbc` and
+    //   `.llvmcmd` sections, so there's nothing extra we need to do.
+    //
+    // * COFF - if we don't do anything the linker will by default copy all
+    //   these sections to the output artifact, not what we want! To subvert
+    //   this we want to flag the sections we inserted here as
+    //   `IMAGE_SCN_LNK_REMOVE`. Unfortunately though LLVM has no native way to
+    //   do this. Thankfully though we can do this with some inline assembly,
+    //   which is easy enough to add via module-level global inline asm.
+    //
+    // * ELF - this is very similar to COFF above. One difference is that these
+    //   sections are removed from the output linked artifact when
+    //   `--gc-sections` is passed, which we pass by default. If that flag isn't
+    //   passed though then these sections will show up in the final output.
+    //   Additionally the flag that we need to set here is `SHF_EXCLUDE`.
+    if is_apple
+        || cgcx.opts.target_triple.triple().starts_with("wasm")
+        || cgcx.opts.target_triple.triple().starts_with("asmjs")
+    {
+        // nothing to do here
+    } else if cgcx.opts.target_triple.triple().contains("windows") {
+        let asm = "
+            .section .llvmbc,\"n\"
+            .section .llvmcmd,\"n\"
+        ";
+        llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
+    } else {
+        let asm = "
+            .section .llvmbc,\"e\"
+            .section .llvmcmd,\"e\"
+        ";
+        llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
+    }
 }
 
 pub unsafe fn with_llvm_pmb(
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index 64158679740..5effde444af 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -40,7 +40,6 @@ use std::sync::Arc;
 
 mod back {
     pub mod archive;
-    pub mod bytecode;
     pub mod lto;
     mod profiling;
     pub mod write;
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index aeb34e5c9c9..ceeb528430f 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -2138,6 +2138,11 @@ extern "C" {
         len: usize,
         Identifier: *const c_char,
     ) -> Option<&Module>;
+    pub fn LLVMRustGetBitcodeSliceFromObjectData(
+        Data: *const u8,
+        len: usize,
+        out_len: &mut usize,
+    ) -> *const u8;
     pub fn LLVMRustThinLTOGetDICompileUnit(
         M: &Module,
         CU1: &mut *mut c_void,