Skip to content

Commit 6f5030f

Browse files
committed
rustc: Fix wasm64 metadata object files
It looks like LLD will detect object files being either 32 or 64-bit depending on any memory present. LLD will additionally reject 32-bit objects during a 64-bit link. Previously metadata objects did not have any memories in them which led LLD to conclude they were 32-bit objects which broke 64-bit targets for wasm. This commit fixes this by ensuring that for 64-bit targets there's a memory object present to get LLD to detect it's a 64-bit target. Additionally this commit moves away from a hand-crafted wasm encoder to the `wasm-encoder` crate on crates.io as the complexity grows for the generated object file. Closes #121460
1 parent 1bb3a9f commit 6f5030f

File tree

5 files changed

+60
-50
lines changed

5 files changed

+60
-50
lines changed

Cargo.lock

+10
Original file line numberDiff line numberDiff line change
@@ -3673,6 +3673,7 @@ dependencies = [
36733673
"thin-vec",
36743674
"thorin-dwp",
36753675
"tracing",
3676+
"wasm-encoder",
36763677
"windows",
36773678
]
36783679

@@ -6128,6 +6129,15 @@ version = "0.2.91"
61286129
source = "registry+https://github.com/rust-lang/crates.io-index"
61296130
checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
61306131

6132+
[[package]]
6133+
name = "wasm-encoder"
6134+
version = "0.200.0"
6135+
source = "registry+https://github.com/rust-lang/crates.io-index"
6136+
checksum = "b9e3fb0c8fbddd78aa6095b850dfeedbc7506cf5f81e633f69cf8f2333ab84b9"
6137+
dependencies = [
6138+
"leb128",
6139+
]
6140+
61316141
[[package]]
61326142
name = "wasmparser"
61336143
version = "0.118.2"

compiler/rustc_codegen_ssa/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ tempfile = "3.2"
3838
thin-vec = "0.2.12"
3939
thorin-dwp = "0.7"
4040
tracing = "0.1"
41+
wasm-encoder = "0.200.0"
4142
# tidy-alphabetical-end
4243

4344
[target.'cfg(unix)'.dependencies]

compiler/rustc_codegen_ssa/src/back/link.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -315,8 +315,11 @@ fn link_rlib<'a>(
315315

316316
let trailing_metadata = match flavor {
317317
RlibFlavor::Normal => {
318-
let (metadata, metadata_position) =
319-
create_wrapper_file(sess, b".rmeta".to_vec(), codegen_results.metadata.raw_data());
318+
let (metadata, metadata_position) = create_wrapper_file(
319+
sess,
320+
".rmeta".to_string(),
321+
codegen_results.metadata.raw_data(),
322+
);
320323
let metadata = emit_wrapper_file(sess, &metadata, tmpdir, METADATA_FILENAME);
321324
match metadata_position {
322325
MetadataPosition::First => {
@@ -384,7 +387,7 @@ fn link_rlib<'a>(
384387
let path = find_native_static_library(filename.as_str(), true, &lib_search_paths, sess);
385388
let src = read(path)
386389
.map_err(|e| sess.dcx().emit_fatal(errors::ReadFileError { message: e }))?;
387-
let (data, _) = create_wrapper_file(sess, b".bundled_lib".to_vec(), &src);
390+
let (data, _) = create_wrapper_file(sess, ".bundled_lib".to_string(), &src);
388391
let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str());
389392
packed_bundled_libs.push(wrapper_file);
390393
} else {

compiler/rustc_codegen_ssa/src/back/metadata.rs

+40-47
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Reading of the rustc metadata for rlibs and dylibs
22
3+
use std::borrow::Cow;
34
use std::fs::File;
45
use std::io::Write;
56
use std::path::Path;
@@ -15,7 +16,6 @@ use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice};
1516
use rustc_metadata::creader::MetadataLoader;
1617
use rustc_metadata::fs::METADATA_FILENAME;
1718
use rustc_metadata::EncodedMetadata;
18-
use rustc_serialize::leb128;
1919
use rustc_session::Session;
2020
use rustc_span::sym;
2121
use rustc_target::abi::Endian;
@@ -434,12 +434,15 @@ pub enum MetadataPosition {
434434
/// automatically removed from the final output.
435435
pub fn create_wrapper_file(
436436
sess: &Session,
437-
section_name: Vec<u8>,
437+
section_name: String,
438438
data: &[u8],
439439
) -> (Vec<u8>, MetadataPosition) {
440440
let Some(mut file) = create_object_file(sess) else {
441441
if sess.target.is_like_wasm {
442-
return (create_metadata_file_for_wasm(data, &section_name), MetadataPosition::First);
442+
return (
443+
create_metadata_file_for_wasm(sess, data, &section_name),
444+
MetadataPosition::First,
445+
);
443446
}
444447

445448
// Targets using this branch don't have support implemented here yet or
@@ -452,7 +455,7 @@ pub fn create_wrapper_file(
452455
} else {
453456
file.add_section(
454457
file.segment_name(StandardSegment::Debug).to_vec(),
455-
section_name,
458+
section_name.into_bytes(),
456459
SectionKind::Debug,
457460
)
458461
};
@@ -524,7 +527,7 @@ pub fn create_compressed_metadata_file(
524527

525528
let Some(mut file) = create_object_file(sess) else {
526529
if sess.target.is_like_wasm {
527-
return create_metadata_file_for_wasm(&packed_metadata, b".rustc");
530+
return create_metadata_file_for_wasm(sess, &packed_metadata, ".rustc");
528531
}
529532
return packed_metadata.to_vec();
530533
};
@@ -624,51 +627,41 @@ pub fn create_compressed_metadata_file_for_xcoff(
624627
/// `data`.
625628
///
626629
/// NB: the `object` crate does not yet have support for writing the the wasm
627-
/// object file format. The format is simple enough that for now an extra crate
628-
/// from crates.io (such as `wasm-encoder`). The file format is:
630+
/// object file format. In lieu of that the `wasm-encoder` crate is used to
631+
/// build a wasm file by hand.
629632
///
630-
/// * 4-byte header "\0asm"
631-
/// * 4-byte version number - 1u32 in little-endian format
632-
/// * concatenated sections, which for this object is always "custom sections"
633-
///
634-
/// Custom sections are then defined by:
635-
/// * 1-byte section identifier - 0 for a custom section
636-
/// * leb-encoded section length (size of the contents beneath this bullet)
637-
/// * leb-encoded custom section name length
638-
/// * custom section name
639-
/// * section contents
640-
///
641-
/// One custom section, `linking`, is added here in accordance with
633+
/// The wasm object file format is defined at
642634
/// <https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md>
643-
/// which is required to inform LLD that this is an object file but it should
644-
/// otherwise basically ignore it if it otherwise looks at it. The linking
645-
/// section currently is defined by a single version byte (2) and then further
646-
/// sections, but we have no more sections, so it's just the byte "2".
635+
/// and mainly consists of a `linking` custom section. In this case the custom
636+
/// section there is empty except for a version marker indicating what format
637+
/// it's in.
647638
///
648-
/// The next custom section is the one we're interested in.
649-
pub fn create_metadata_file_for_wasm(data: &[u8], section_name: &[u8]) -> Vec<u8> {
650-
let mut bytes = b"\0asm\x01\0\0\0".to_vec();
651-
652-
let mut append_custom_section = |section_name: &[u8], data: &[u8]| {
653-
let mut section_name_len = [0; leb128::max_leb128_len::<usize>()];
654-
let off = leb128::write_usize_leb128(&mut section_name_len, section_name.len());
655-
let section_name_len = &section_name_len[..off];
656-
657-
let mut section_len = [0; leb128::max_leb128_len::<usize>()];
658-
let off = leb128::write_usize_leb128(
659-
&mut section_len,
660-
data.len() + section_name_len.len() + section_name.len(),
639+
/// The main purpose of this is to contain a custom section with `section_name`,
640+
/// which is then appended after `linking`.
641+
///
642+
/// As a further detail the object needs to have a 64-bit memory if `wasm64` is
643+
/// the target or otherwise it's interpreted as a 32-bit object which is
644+
/// incompatible with 64-bit ones.
645+
pub fn create_metadata_file_for_wasm(sess: &Session, data: &[u8], section_name: &str) -> Vec<u8> {
646+
assert!(sess.target.is_like_wasm);
647+
let mut module = wasm_encoder::Module::new();
648+
let mut imports = wasm_encoder::ImportSection::new();
649+
650+
if sess.target.pointer_width == 64 {
651+
imports.import(
652+
"env",
653+
"__linear_memory",
654+
wasm_encoder::MemoryType { minimum: 0, maximum: None, memory64: true, shared: false },
661655
);
662-
let section_len = &section_len[..off];
663-
664-
bytes.push(0u8);
665-
bytes.extend_from_slice(section_len);
666-
bytes.extend_from_slice(section_name_len);
667-
bytes.extend_from_slice(section_name);
668-
bytes.extend_from_slice(data);
669-
};
656+
}
670657

671-
append_custom_section(b"linking", &[2]);
672-
append_custom_section(section_name, data);
673-
bytes
658+
if imports.len() > 0 {
659+
module.section(&imports);
660+
}
661+
module.section(&wasm_encoder::CustomSection {
662+
name: "linking".into(),
663+
data: Cow::Borrowed(&[2]),
664+
});
665+
module.section(&wasm_encoder::CustomSection { name: section_name.into(), data: data.into() });
666+
module.finish()
674667
}

src/tools/tidy/src/deps.rs

+3
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ const EXCEPTIONS: ExceptionList = &[
9292
("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0 // cargo/... (because of serde)
9393
("self_cell", "Apache-2.0"), // rustc (fluent translations)
9494
("snap", "BSD-3-Clause"), // rustc
95+
("wasm-encoder", "Apache-2.0 WITH LLVM-exception"), // rustc
9596
("wasmparser", "Apache-2.0 WITH LLVM-exception"), // rustc
9697
// tidy-alphabetical-end
9798
];
@@ -267,6 +268,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
267268
"jemalloc-sys",
268269
"jobserver",
269270
"lazy_static",
271+
"leb128",
270272
"libc",
271273
"libloading",
272274
"linux-raw-sys",
@@ -380,6 +382,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
380382
"valuable",
381383
"version_check",
382384
"wasi",
385+
"wasm-encoder",
383386
"wasmparser",
384387
"winapi",
385388
"winapi-i686-pc-windows-gnu",

0 commit comments

Comments
 (0)