11// This module maps the data structure of different versions of goblin to the
22// same internal structure.
3- use crate :: machine:: { VERSION1 , VERSION3 } ;
3+ use crate :: machine:: { VERSION0 , VERSION1 , VERSION2 , VERSION3 } ;
44use crate :: memory:: { FLAG_EXECUTABLE , FLAG_FREEZED , round_page_down, round_page_up} ;
55use crate :: { Error , Register } ;
66use bytes:: Bytes ;
@@ -143,6 +143,24 @@ pub struct CFI {
143143 pub lp_func_sig : bool ,
144144}
145145
146+ impl From < u8 > for CFI {
147+ fn from ( byte : u8 ) -> Self {
148+ Self {
149+ lp_unlabeled : byte & 0b0000_0001 != 0 ,
150+ ss : byte & 0b0000_0010 != 0 ,
151+ lp_func_sig : byte & 0b0000_0100 != 0 ,
152+ }
153+ }
154+ }
155+
156+ impl From < CFI > for u8 {
157+ fn from ( val : CFI ) -> Self {
158+ ( if val. lp_unlabeled { 0b0000_0001 } else { 0 } )
159+ | ( if val. ss { 0b0000_0010 } else { 0 } )
160+ | ( if val. lp_func_sig { 0b0000_0100 } else { 0 } )
161+ }
162+ }
163+
146164#[ derive( Default ) ]
147165pub struct ParseElfPortableData {
148166 pub entry : u64 ,
@@ -154,10 +172,7 @@ pub struct ParseElfPortableData {
154172impl ParseElfPortableData {
155173 pub fn from_v0 < R : Register > ( program : & Bytes ) -> Result < Self , Error > {
156174 use goblin_v023:: container:: Ctx ;
157- use goblin_v023:: elf:: {
158- Header , program_header:: ProgramHeader as GoblinProgramHeader ,
159- section_header:: SectionHeader as GoblinSectionHeader ,
160- } ;
175+ use goblin_v023:: elf:: { Header , program_header:: ProgramHeader as GoblinProgramHeader } ;
161176 let header = program. pread :: < Header > ( 0 ) ?;
162177 let container = header. container ( ) . map_err ( |_e| Error :: ElfBits ) ?;
163178 let endianness = header. endianness ( ) . map_err ( |_e| Error :: ElfBits ) ?;
@@ -174,15 +189,35 @@ impl ParseElfPortableData {
174189 . iter ( )
175190 . map ( ProgramHeader :: from_v0)
176191 . collect ( ) ;
177- let section_headers = GoblinSectionHeader :: parse (
192+ let section_headers = vec ! [ ] ;
193+ Ok ( Self {
194+ entry : header. e_entry ,
195+ program_headers,
196+ section_headers,
197+ shstrtab_offset : header. e_shstrndx as usize ,
198+ } )
199+ }
200+
201+ pub fn from_v1 < R : Register > ( program : & Bytes ) -> Result < Self , Error > {
202+ use goblin_v040:: container:: Ctx ;
203+ use goblin_v040:: elf:: { Header , program_header:: ProgramHeader as GoblinProgramHeader } ;
204+ let header = program. pread :: < Header > ( 0 ) ?;
205+ let container = header. container ( ) . map_err ( |_e| Error :: ElfBits ) ?;
206+ let endianness = header. endianness ( ) . map_err ( |_e| Error :: ElfBits ) ?;
207+ if R :: BITS != if container. is_big ( ) { 64 } else { 32 } {
208+ return Err ( Error :: ElfBits ) ;
209+ }
210+ let ctx = Ctx :: new ( container, endianness) ;
211+ let program_headers = GoblinProgramHeader :: parse (
178212 program,
179- header. e_shoff as usize ,
180- header. e_shnum as usize ,
213+ header. e_phoff as usize ,
214+ header. e_phnum as usize ,
181215 ctx,
182216 ) ?
183217 . iter ( )
184- . map ( SectionHeader :: from_v0 )
218+ . map ( ProgramHeader :: from_v1 )
185219 . collect ( ) ;
220+ let section_headers = vec ! [ ] ;
186221 Ok ( Self {
187222 entry : header. e_entry ,
188223 program_headers,
@@ -191,7 +226,7 @@ impl ParseElfPortableData {
191226 } )
192227 }
193228
194- pub fn from_v1 < R : Register > ( program : & Bytes ) -> Result < Self , Error > {
229+ pub fn from_v3 < R : Register > ( program : & Bytes ) -> Result < Self , Error > {
195230 use goblin_v040:: container:: Ctx ;
196231 use goblin_v040:: elf:: {
197232 Header , program_header:: ProgramHeader as GoblinProgramHeader ,
@@ -256,15 +291,15 @@ fn parse_gnu_property_note(note_data: &[u8]) -> Result<CFI, Error> {
256291 ) ) ;
257292 }
258293 offset += 8 ;
259- if pr_type == GNU_PROPERTY_RISCV_FEATURE_1_AND && pr_datasz >= 4 {
260- if offset + 4 <= note_data . len ( ) {
261- buf . copy_from_slice ( & note_data [ offset..offset + 4 ] ) ;
262- let feature_flags = u32 :: from_le_bytes ( buf ) ;
263- cfi . lp_unlabeled =
264- feature_flags & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED != 0 ;
265- cfi. ss = feature_flags & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS != 0 ;
266- cfi. lp_func_sig = feature_flags & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG != 0 ;
267- }
294+ if pr_type == GNU_PROPERTY_RISCV_FEATURE_1_AND
295+ && pr_datasz >= 4
296+ && offset + 4 <= note_data . len ( )
297+ {
298+ buf . copy_from_slice ( & note_data [ offset..offset + 4 ] ) ;
299+ let feature_flags = u32 :: from_le_bytes ( buf ) ;
300+ cfi. lp_unlabeled = feature_flags & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED != 0 ;
301+ cfi. ss = feature_flags & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS != 0 ;
302+ cfi . lp_func_sig = feature_flags & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_FUNC_SIG != 0 ;
268303 }
269304 // Align to 8 bytes for next property.
270305 let aligned_datasz = ( pr_datasz + 7 ) & !7 ;
@@ -276,10 +311,11 @@ fn parse_gnu_property_note(note_data: &[u8]) -> Result<CFI, Error> {
276311pub fn parse_elf < R : Register > ( program : & Bytes , version : u32 ) -> Result < ProgramMetadata , Error > {
277312 // We did not use Elf::parse here to avoid triggering potential bugs in goblin.
278313 // * https://github.com/nervosnetwork/ckb-vm/issues/143
279- let pepd = if version < VERSION1 {
280- ParseElfPortableData :: from_v0 :: < R > ( program) ?
281- } else {
282- ParseElfPortableData :: from_v1 :: < R > ( program) ?
314+ let pepd = match version {
315+ VERSION0 => ParseElfPortableData :: from_v0 :: < R > ( program) ?,
316+ VERSION1 | VERSION2 => ParseElfPortableData :: from_v1 :: < R > ( program) ?,
317+ VERSION3 => ParseElfPortableData :: from_v3 :: < R > ( program) ?,
318+ _ => ParseElfPortableData :: from_v3 :: < R > ( program) ?,
283319 } ;
284320 let mut cfi = CFI :: default ( ) ;
285321 // CFI will only be parsed when using version 3. This avoids errors in older code from
0 commit comments