Skip to content
This repository was archived by the owner on Oct 13, 2023. It is now read-only.

Commit 04e31f3

Browse files
authored
Simplify global state management in adapter (#13)
* Simplify global state management in adapter I was looking recently to implement args-related syscalls but that would require yet-more globals and yet-more state to be managed. Instead of adding a slew of new globals for this which are all manually kept in sync I opted to instead redesign how global state is managed in the adapter. The previous multiple `global`s are all removed in favor of just one, as sort of a "tls slot" of sorts. This one remaining slot points to a one-time-allocated `State` object which internally stores information like buffer metadata, fd information, etc. Along the way I've also simplified syscalls with new methods and `?`-using closures. * Turn off incremental for dev builds Helps with CGU splitting and ensuring that appropriate code is produced even without `--release`. * Review comments * Add accessors with specific errors * Update handling of `*_global_ptr` * Update internal mutability around path buffer Use an `UnsafeCell` layering to indicate that mutation may happen through `&T`.
1 parent 40861ae commit 04e31f3

File tree

4 files changed

+533
-597
lines changed

4 files changed

+533
-597
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ panic = 'abort'
2424

2525
# Make dev look like a release build since this adapter module won't work with
2626
# a debug build that uses data segments and such.
27-
[profile.dev]
27+
[profile.dev.package.wasi_snapshot_preview1]
28+
incremental = false
2829
opt-level = 3
2930
debug = 0
30-
panic = 'abort'
3131
# Omit integer overflow checks, which include failure messages which require
3232
# string initializers.
3333
overflow-checks = false

build.rs

Lines changed: 82 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,8 @@ use std::path::PathBuf;
44
fn main() {
55
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
66

7-
let mut function_names = Vec::new();
8-
function_names.push("replace_realloc_global_ptr".to_owned());
9-
function_names.push("replace_realloc_global_len".to_owned());
10-
function_names.push("replace_fds".to_owned());
11-
12-
let mut global_names = Vec::new();
13-
global_names.push("internal_realloc_global_ptr".to_owned());
14-
global_names.push("internal_realloc_global_len".to_owned());
15-
global_names.push("internal_fds".to_owned());
16-
17-
let wasm = build_raw_intrinsics(&function_names, &global_names);
18-
let archive = build_archive(&wasm, &function_names);
7+
let wasm = build_raw_intrinsics();
8+
let archive = build_archive(&wasm);
199

2010
std::fs::write(out_dir.join("libwasm-raw-intrinsics.a"), &archive).unwrap();
2111
println!("cargo:rustc-link-lib=static=wasm-raw-intrinsics");
@@ -31,83 +21,69 @@ fn main() {
3121
/// ```rust
3222
/// std::arch::global_asm!(
3323
/// "
34-
/// .globaltype internal_realloc_global_ptr, i32
35-
/// internal_realloc_global_ptr:
36-
/// .globaltype internal_realloc_global_len, i32
37-
/// internal_realloc_global_len:
38-
/// .globaltype internal_fds, i32
39-
/// internal_fds:
24+
/// .globaltype internal_global_ptr, i32
25+
/// internal_global_ptr:
4026
/// "
4127
/// );
4228
///
4329
/// #[no_mangle]
44-
/// extern "C" fn replace_realloc_global_ptr(val: *mut u8) -> *mut u8 {
30+
/// extern "C" fn get_global_ptr() -> *mut u8 {
4531
/// unsafe {
4632
/// let ret: *mut u8;
4733
/// std::arch::asm!(
4834
/// "
49-
/// global.get internal_realloc_global_ptr
50-
/// local.get {}
51-
/// global.set internal_realloc_global_ptr
35+
/// global.get internal_global_ptr
5236
/// ",
5337
/// out(local) ret,
54-
/// in(local) val,
5538
/// options(nostack, readonly)
5639
/// );
5740
/// ret
5841
/// }
5942
/// }
6043
///
6144
/// #[no_mangle]
62-
/// extern "C" fn replace_realloc_global_len(val: usize) -> usize {
45+
/// extern "C" fn set_global_ptr(val: *mut u8) {
6346
/// unsafe {
64-
/// let ret: usize;
6547
/// std::arch::asm!(
6648
/// "
67-
/// global.get internal_realloc_global_len
6849
/// local.get {}
69-
/// global.set internal_realloc_global_len
50+
/// global.set internal_global_ptr
7051
/// ",
71-
/// out(local) ret,
7252
/// in(local) val,
7353
/// options(nostack, readonly)
7454
/// );
75-
/// ret
7655
/// }
7756
/// }
7857
/// ```
7958
///
8059
/// The main trickiness here is getting the `reloc.CODE` and `linking` sections
8160
/// right.
82-
fn build_raw_intrinsics(function_names: &[String], global_names: &[String]) -> Vec<u8> {
61+
fn build_raw_intrinsics() -> Vec<u8> {
8362
use wasm_encoder::Instruction::*;
8463
use wasm_encoder::*;
8564

8665
let mut module = Module::new();
8766

88-
// All our functions have the same type, i32 -> i32
8967
let mut types = TypeSection::new();
90-
types.function([ValType::I32], [ValType::I32]);
68+
types.function([], [ValType::I32]);
69+
types.function([ValType::I32], []);
9170
module.section(&types);
9271

9372
// Declare the functions, using the type we just added.
9473
let mut funcs = FunctionSection::new();
95-
for _ in function_names {
96-
funcs.function(0);
97-
}
74+
funcs.function(0);
75+
funcs.function(1);
9876
module.section(&funcs);
9977

10078
// Declare the globals.
10179
let mut globals = GlobalSection::new();
102-
for _ in global_names {
103-
globals.global(
104-
GlobalType {
105-
val_type: ValType::I32,
106-
mutable: true,
107-
},
108-
&ConstExpr::i32_const(0),
109-
);
110-
}
80+
globals.global(
81+
GlobalType {
82+
val_type: ValType::I32,
83+
mutable: true,
84+
},
85+
&ConstExpr::i32_const(0),
86+
);
11187
module.section(&globals);
11288

11389
// Here the `code` section is defined. This is tricky because an offset is
@@ -117,43 +93,44 @@ fn build_raw_intrinsics(function_names: &[String], global_names: &[String]) -> V
11793
//
11894
// First the function body is created and then it's appended into a code
11995
// section.
120-
let mut body = Vec::new();
121-
0u32.encode(&mut body); // no locals
122-
let global_offset0 = body.len() + 1;
123-
// global.get 0 ;; but with maximal encoding of the 0
124-
body.extend_from_slice(&[0x23, 0x80, 0x80, 0x80, 0x80, 0x00]);
125-
LocalGet(0).encode(&mut body);
126-
let global_offset1 = body.len() + 1;
127-
// global.set 0 ;; but with maximal encoding of the 0
128-
body.extend_from_slice(&[0x24, 0x81, 0x80, 0x80, 0x80, 0x00]);
129-
End.encode(&mut body);
130-
131-
let mut body_offsets = Vec::new();
13296

13397
let mut code = Vec::new();
134-
function_names.len().encode(&mut code);
135-
for _ in function_names {
98+
2u32.encode(&mut code);
99+
100+
// get_global_ptr
101+
let global_offset0 = {
102+
let mut body = Vec::new();
103+
0u32.encode(&mut body); // no locals
104+
let global_offset = body.len() + 1;
105+
// global.get 0 ;; but with maximal encoding of the 0
106+
body.extend_from_slice(&[0x23, 0x80, 0x80, 0x80, 0x80, 0x00]);
107+
End.encode(&mut body);
136108
body.len().encode(&mut code); // length of the function
137-
body_offsets.push(code.len());
109+
let offset = code.len() + global_offset;
138110
code.extend_from_slice(&body); // the function itself
139-
}
111+
offset
112+
};
113+
114+
// set_global_ptr
115+
let global_offset1 = {
116+
let mut body = Vec::new();
117+
0u32.encode(&mut body); // no locals
118+
LocalGet(0).encode(&mut body);
119+
let global_offset = body.len() + 1;
120+
// global.set 0 ;; but with maximal encoding of the 0
121+
body.extend_from_slice(&[0x24, 0x80, 0x80, 0x80, 0x80, 0x00]);
122+
End.encode(&mut body);
123+
body.len().encode(&mut code); // length of the function
124+
let offset = code.len() + global_offset;
125+
code.extend_from_slice(&body); // the function itself
126+
offset
127+
};
128+
140129
module.section(&RawSection {
141130
id: SectionId::Code as u8,
142131
data: &code,
143132
});
144133

145-
// Calculate the relocation offsets within the `code` section itself by
146-
// adding the start of where the body was placed to the offset within the
147-
// body.
148-
let global_offsets0 = body_offsets
149-
.iter()
150-
.map(|x| x + global_offset0)
151-
.collect::<Vec<_>>();
152-
let global_offsets1 = body_offsets
153-
.iter()
154-
.map(|x| x + global_offset1)
155-
.collect::<Vec<_>>();
156-
157134
// Here the linking section is constructed. There are two symbols described
158135
// here, one for the function that we injected and one for the global
159136
// that was injected. The injected global here is referenced in the
@@ -167,21 +144,22 @@ fn build_raw_intrinsics(function_names: &[String], global_names: &[String]) -> V
167144

168145
linking.push(0x08); // `WASM_SYMBOL_TABLE`
169146
let mut subsection = Vec::new();
170-
6u32.encode(&mut subsection); // 6 symbols (3 functions + 3 globals)
147+
3u32.encode(&mut subsection); // 3 symbols (2 functions + 1 global)
148+
149+
subsection.push(0x00); // SYMTAB_FUNCTION
150+
0x00.encode(&mut subsection); // flags
151+
0u32.encode(&mut subsection); // function index
152+
"get_global_ptr".encode(&mut subsection); // symbol name
171153

172-
for (index, name) in function_names.iter().enumerate() {
173-
subsection.push(0x00); // SYMTAB_FUNCTION
174-
0x00.encode(&mut subsection); // flags
175-
index.encode(&mut subsection); // function index
176-
name.encode(&mut subsection); // symbol name
177-
}
154+
subsection.push(0x00); // SYMTAB_FUNCTION
155+
0x00.encode(&mut subsection); // flags
156+
1u32.encode(&mut subsection); // function index
157+
"set_global_ptr".encode(&mut subsection); // symbol name
178158

179-
for (index, name) in global_names.iter().enumerate() {
180-
subsection.push(0x02); // SYMTAB_GLOBAL
181-
0x02.encode(&mut subsection); // flags
182-
index.encode(&mut subsection); // global index
183-
name.encode(&mut subsection); // symbol name
184-
}
159+
subsection.push(0x02); // SYMTAB_GLOBAL
160+
0x02.encode(&mut subsection); // flags
161+
0u32.encode(&mut subsection); // global index
162+
"internal_global_ptr".encode(&mut subsection); // symbol name
185163

186164
subsection.encode(&mut linking);
187165
module.section(&CustomSection {
@@ -195,15 +173,15 @@ fn build_raw_intrinsics(function_names: &[String], global_names: &[String]) -> V
195173
{
196174
let mut reloc = Vec::new();
197175
3u32.encode(&mut reloc); // target section (code is the 4th section, 3 when 0-indexed)
198-
6u32.encode(&mut reloc); // 6 relocations
199-
for index in 0..global_names.len() {
200-
reloc.push(0x07); // R_WASM_GLOBAL_INDEX_LEB
201-
global_offsets0[index as usize].encode(&mut reloc); // offset
202-
(function_names.len() + index).encode(&mut reloc); // symbol index
203-
reloc.push(0x07); // R_WASM_GLOBAL_INDEX_LEB
204-
global_offsets1[index as usize].encode(&mut reloc); // offset
205-
(function_names.len() + index).encode(&mut reloc); // symbol index
206-
}
176+
2u32.encode(&mut reloc); // 2 relocations
177+
178+
reloc.push(0x07); // R_WASM_GLOBAL_INDEX_LEB
179+
global_offset0.encode(&mut reloc); // offset
180+
2u32.encode(&mut reloc); // symbol index
181+
182+
reloc.push(0x07); // R_WASM_GLOBAL_INDEX_LEB
183+
global_offset1.encode(&mut reloc); // offset
184+
2u32.encode(&mut reloc); // symbol index
207185

208186
module.section(&CustomSection {
209187
name: "reloc.CODE",
@@ -220,7 +198,7 @@ fn build_raw_intrinsics(function_names: &[String], global_names: &[String]) -> V
220198
///
221199
/// Like above this is still tricky, mainly around the production of the symbol
222200
/// table.
223-
fn build_archive(wasm: &[u8], function_names: &[String]) -> Vec<u8> {
201+
fn build_archive(wasm: &[u8]) -> Vec<u8> {
224202
use object::{bytes_of, endian::BigEndian, U32Bytes};
225203

226204
let mut archive = Vec::new();
@@ -238,17 +216,11 @@ fn build_archive(wasm: &[u8], function_names: &[String]) -> Vec<u8> {
238216
// easier. Note though we don't know the offset of our `intrinsics.o` up
239217
// front so it's left as 0 for now and filled in later.
240218
let mut symbol_table = Vec::new();
241-
symbol_table.extend_from_slice(bytes_of(&U32Bytes::new(
242-
BigEndian,
243-
function_names.len().try_into().unwrap(),
244-
)));
245-
for _ in function_names {
246-
symbol_table.extend_from_slice(bytes_of(&U32Bytes::new(BigEndian, 0)));
247-
}
248-
for name in function_names {
249-
symbol_table.extend_from_slice(name.as_bytes());
250-
symbol_table.push(0x00);
251-
}
219+
symbol_table.extend_from_slice(bytes_of(&U32Bytes::new(BigEndian, 2)));
220+
symbol_table.extend_from_slice(bytes_of(&U32Bytes::new(BigEndian, 0)));
221+
symbol_table.extend_from_slice(bytes_of(&U32Bytes::new(BigEndian, 0)));
222+
symbol_table.extend_from_slice(b"get_global_ptr\0");
223+
symbol_table.extend_from_slice(b"set_global_ptr\0");
252224

253225
archive.extend_from_slice(bytes_of(&object::archive::Header {
254226
name: *b"/ ",
@@ -277,6 +249,10 @@ fn build_archive(wasm: &[u8], function_names: &[String]) -> Vec<u8> {
277249
BigEndian,
278250
member_offset.try_into().unwrap(),
279251
)));
252+
archive[symtab_offset + 8..][..4].copy_from_slice(bytes_of(&U32Bytes::new(
253+
BigEndian,
254+
member_offset.try_into().unwrap(),
255+
)));
280256

281257
archive.extend_from_slice(object::bytes_of(&object::archive::Header {
282258
name: *b"intrinsics.o ",

0 commit comments

Comments
 (0)