@@ -5,9 +5,13 @@ use crate::prelude::*;
55use crate :: runtime:: vm:: MmapVec ;
66use alloc:: sync:: Arc ;
77use core:: ops:: Range ;
8- use object:: SectionFlags ;
9- use object:: endian:: Endianness ;
10- use object:: read:: { Object , ObjectSection , elf:: ElfFile64 } ;
8+ use object:: SectionIndex ;
9+ use object:: read:: elf:: SectionTable ;
10+ use object:: {
11+ elf:: { FileHeader64 , SectionHeader64 } ,
12+ endian:: Endianness ,
13+ read:: elf:: { FileHeader as _, SectionHeader as _} ,
14+ } ;
1115use wasmtime_environ:: { Trap , lookup_trap_code, obj} ;
1216use wasmtime_unwinder:: ExceptionTable ;
1317
@@ -116,9 +120,23 @@ impl CodeMemory {
116120 /// The returned `CodeMemory` manages the internal `MmapVec` and the
117121 /// `publish` method is used to actually make the memory executable.
118122 pub fn new ( engine : & Engine , mmap : MmapVec ) -> Result < Self > {
119- let obj = ElfFile64 :: < Endianness > :: parse ( & mmap[ ..] )
123+ let mmap_data = & * mmap;
124+ let header = FileHeader64 :: < Endianness > :: parse ( mmap_data)
120125 . map_err ( obj:: ObjectCrateErrorWrapper )
121- . with_context ( || "failed to parse internal compilation artifact" ) ?;
126+ . context ( "failed to parse precompiled artifact as an ELF" ) ?;
127+ let endian = header
128+ . endian ( )
129+ . context ( "failed to parse header endianness" ) ?;
130+
131+ let section_headers = header
132+ . section_headers ( endian, mmap_data)
133+ . context ( "failed to parse section headers" ) ?;
134+ let strings = header
135+ . section_strings ( endian, mmap_data, section_headers)
136+ . context ( "failed to parse strings table" ) ?;
137+ let sections = header
138+ . sections ( endian, mmap_data)
139+ . context ( "failed to parse sections table" ) ?;
122140
123141 let mut text = 0 ..0 ;
124142 let mut unwind = 0 ..0 ;
@@ -135,42 +153,53 @@ impl CodeMemory {
135153 let mut func_name_data = 0 ..0 ;
136154 let mut info_data = 0 ..0 ;
137155 let mut wasm_dwarf = 0 ..0 ;
138- for section in obj. sections ( ) {
139- let data = section. data ( ) . map_err ( obj:: ObjectCrateErrorWrapper ) ?;
140- let name = section. name ( ) . map_err ( obj:: ObjectCrateErrorWrapper ) ?;
156+ for section_header in sections. iter ( ) {
157+ let data = section_header
158+ . data ( endian, mmap_data)
159+ . map_err ( obj:: ObjectCrateErrorWrapper ) ?;
160+ let name = section_name ( endian, strings, section_header) ?;
141161 let range = subslice_range ( data, & mmap) ;
142162
143163 // Double-check that sections are all aligned properly.
144- if section. align ( ) != 0 && data. len ( ) != 0 {
145- if ( data. as_ptr ( ) as u64 - mmap. as_ptr ( ) as u64 ) % section. align ( ) != 0 {
146- bail ! (
147- "section `{}` isn't aligned to {:#x}" ,
148- section. name( ) . unwrap_or( "ERROR" ) ,
149- section. align( )
150- ) ;
151- }
164+ let section_align = usize:: try_from ( section_header. sh_addralign ( endian) ) ?;
165+ if section_align != 0 && data. len ( ) != 0 {
166+ let section_offset = data. as_ptr ( ) . addr ( ) - mmap. as_ptr ( ) . addr ( ) ;
167+ ensure ! (
168+ section_offset % section_align == 0 ,
169+ "section {name:?} isn't aligned to {section_align:#x}" ,
170+ ) ;
171+ }
172+
173+ // Check that we don't have any relocations, which would make
174+ // loading precompiled Wasm modules slower and also force them to
175+ // get paged into memory from disk.
176+ //
177+ // We avoid using things like Cranelift's `floor`, `ceil`,
178+ // etc... operators in the Wasm-to-CLIF translator specifically to
179+ // avoid having to do any relocations here. This also ensures that
180+ // all builtins use the same trampoline mechanism.
181+ //
182+ // We do, however, allow relocations in `.debug_*` DWARF sections.
183+ if let Some ( target_section) = reloc_section_target ( & sections, section_header, endian) ? {
184+ let target_name = section_name ( endian, strings, target_section) ?;
185+ ensure ! (
186+ target_name. starts_with( ".debug_" ) ,
187+ "section {target_name:?} has unexpected relocations \
188+ (defined in section {name:?})",
189+ ) ;
152190 }
153191
154192 match name {
155193 obj:: ELF_WASM_BTI => match data. len ( ) {
156194 1 => enable_branch_protection = Some ( data[ 0 ] != 0 ) ,
157- _ => bail ! ( "invalid ` {name}` section" ) ,
195+ _ => bail ! ( "invalid {name:?} section" ) ,
158196 } ,
159197 ".text" => {
160198 text = range;
161199
162- if let SectionFlags :: Elf { sh_flags } = section. flags ( ) {
163- if sh_flags & obj:: SH_WASMTIME_NOT_EXECUTED != 0 {
164- needs_executable = false ;
165- }
200+ if section_header. sh_flags ( endian) & obj:: SH_WASMTIME_NOT_EXECUTED != 0 {
201+ needs_executable = false ;
166202 }
167-
168- // Assert that Cranelift hasn't inserted any calls that need to be
169- // relocated. We avoid using things like Cranelift's floor/ceil/etc.
170- // operators in the Wasm-to-Cranelift translator specifically to
171- // avoid having to do any relocations here. This also ensures that
172- // all builtins use the same trampoline mechanism.
173- assert ! ( section. relocations( ) . next( ) . is_none( ) ) ;
174203 }
175204 #[ cfg( has_host_compiler_backend) ]
176205 crate :: runtime:: vm:: UnwindRegistration :: SECTION_NAME => unwind = range,
@@ -183,14 +212,24 @@ impl CodeMemory {
183212 obj:: ELF_NAME_DATA => func_name_data = range,
184213 obj:: ELF_WASMTIME_INFO => info_data = range,
185214 obj:: ELF_WASMTIME_DWARF => wasm_dwarf = range,
215+
186216 #[ cfg( feature = "debug-builtins" ) ]
187217 ".debug_info" => has_native_debug_info = true ,
188218
189- _ => log:: debug!( "ignoring section {name}" ) ,
219+ // These sections are expected, but we do not need to retain any
220+ // info about them.
221+ "" | ".symtab" | ".strtab" | ".shstrtab" | ".xdata" | obj:: ELF_WASM_ENGINE => {
222+ log:: debug!( "ignoring section {name:?}" )
223+ }
224+ _ if name. starts_with ( ".debug_" ) || name. starts_with ( ".rela.debug_" ) => {
225+ log:: debug!( "ignoring debug section {name:?}" )
226+ }
227+
228+ _ => bail ! ( "unexpected section {name:?} in Wasm compilation artifact" ) ,
190229 }
191230 }
192231
193- // require mutability even when this is turned off
232+ // Silence unused `mut` warning.
194233 #[ cfg( not( has_host_compiler_backend) ) ]
195234 let _ = & mut unwind;
196235
@@ -546,6 +585,49 @@ impl CodeMemory {
546585 }
547586}
548587
588+ fn section_name < ' a > (
589+ endian : Endianness ,
590+ strings : object:: StringTable < ' a > ,
591+ section_header : & SectionHeader64 < Endianness > ,
592+ ) -> Result < & ' a str > {
593+ let name = section_header
594+ . name ( endian, strings)
595+ . map_err ( obj:: ObjectCrateErrorWrapper ) ?;
596+ Ok ( str:: from_utf8 ( name) . context ( "invalid section name in Wasm compilation artifact" ) ?)
597+ }
598+
599+ fn is_reloc_section ( section_header : & SectionHeader64 < Endianness > , endian : Endianness ) -> bool {
600+ let sh_type = section_header. sh_type ( endian) ;
601+ matches ! (
602+ sh_type,
603+ object:: elf:: SHT_REL | object:: elf:: SHT_RELA | object:: elf:: SHT_CREL
604+ )
605+ }
606+
607+ fn reloc_section_target < ' a > (
608+ sections : & ' a SectionTable < ' a , FileHeader64 < Endianness > , & ' a [ u8 ] > ,
609+ section : & ' a SectionHeader64 < Endianness > ,
610+ endian : Endianness ,
611+ ) -> Result < Option < & ' a SectionHeader64 < Endianness > > > {
612+ if !is_reloc_section ( & section, endian) {
613+ return Ok ( None ) ;
614+ }
615+
616+ let sh_info = section. info_link ( endian) ;
617+
618+ // Dynamic relocation.
619+ if sh_info == SectionIndex ( 0 ) {
620+ return Ok ( None ) ;
621+ }
622+
623+ ensure ! (
624+ sh_info. 0 < sections. len( ) ,
625+ "invalid ELF `sh_info` for relocation section" ,
626+ ) ;
627+
628+ Ok ( Some ( sections. section ( sh_info) ?) )
629+ }
630+
549631/// Returns the range of `inner` within `outer`, such that `outer[range]` is the
550632/// same as `inner`.
551633///
0 commit comments