@@ -4,7 +4,7 @@ use std::path::{Path, PathBuf};
44
55use  rustc_abi:: Endian ; 
66use  rustc_data_structures:: base_n:: { CASE_INSENSITIVE ,  ToBaseN } ; 
7- use  rustc_data_structures:: fx:: FxIndexMap ; 
7+ use  rustc_data_structures:: fx:: { FxHashMap ,   FxIndexMap } ; 
88use  rustc_data_structures:: stable_hasher:: StableHasher ; 
99use  rustc_hashes:: Hash128 ; 
1010use  rustc_session:: Session ; 
@@ -214,7 +214,7 @@ pub(super) fn create_raw_dylib_elf_stub_shared_objects<'a>(
214214/// It exports all the provided symbols, but is otherwise empty. 
215215fn  create_elf_raw_dylib_stub ( sess :  & Session ,  soname :  & str ,  symbols :  & [ DllImport ] )  -> Vec < u8 >  { 
216216    use  object:: write:: elf as  write; 
217-     use  object:: { Architecture ,  elf} ; 
217+     use  object:: { AddressSize ,   Architecture ,  elf} ; 
218218
219219    let  mut  stub_buf = Vec :: new ( ) ; 
220220
@@ -226,54 +226,94 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
226226    // It is important that the order of reservation matches the order of writing. 
227227    // The object crate contains many debug asserts that fire if you get this wrong. 
228228
229+     let  Some ( ( arch,  sub_arch) )  = sess. target . object_architecture ( & sess. unstable_target_features ) 
230+     else  { 
231+         sess. dcx ( ) . fatal ( format ! ( 
232+             "raw-dylib is not supported for the architecture `{}`" , 
233+             sess. target. arch
234+         ) ) ; 
235+     } ; 
236+ 
229237    let  endianness = match  sess. target . options . endian  { 
230238        Endian :: Little  => object:: Endianness :: Little , 
231239        Endian :: Big  => object:: Endianness :: Big , 
232240    } ; 
233-     let  mut  stub = write:: Writer :: new ( endianness,  true ,  & mut  stub_buf) ; 
241+ 
242+     let  is_64 = match  arch. address_size ( )  { 
243+         Some ( AddressSize :: U8  | AddressSize :: U16  | AddressSize :: U32 )  => false , 
244+         Some ( AddressSize :: U64 )  => true , 
245+         _ => sess. dcx ( ) . fatal ( format ! ( 
246+             "raw-dylib is not supported for the architecture `{}`" , 
247+             sess. target. arch
248+         ) ) , 
249+     } ; 
250+ 
251+     let  mut  stub = write:: Writer :: new ( endianness,  is_64,  & mut  stub_buf) ; 
252+ 
253+     let  mut  vers = Vec :: new ( ) ; 
254+     let  mut  vers_map = FxHashMap :: default ( ) ; 
255+     let  mut  syms = Vec :: new ( ) ; 
256+ 
257+     for  symbol in  symbols { 
258+         let  symbol_name = symbol. name . as_str ( ) ; 
259+         if  let  Some ( ( name,  version_name) )  = symbol_name. split_once ( '@' )  { 
260+             assert ! ( !version_name. contains( '@' ) ) ; 
261+             let  dynstr = stub. add_dynamic_string ( name. as_bytes ( ) ) ; 
262+             let  ver = if  let  Some ( & ver_id)  = vers_map. get ( version_name)  { 
263+                 ver_id
264+             }  else  { 
265+                 let  id = vers. len ( ) ; 
266+                 vers_map. insert ( version_name,  id) ; 
267+                 let  dynstr = stub. add_dynamic_string ( version_name. as_bytes ( ) ) ; 
268+                 vers. push ( ( version_name,  dynstr) ) ; 
269+                 id
270+             } ; 
271+             syms. push ( ( name,  dynstr,  Some ( ver) ) ) ; 
272+         }  else  { 
273+             let  dynstr = stub. add_dynamic_string ( symbol_name. as_bytes ( ) ) ; 
274+             syms. push ( ( symbol_name,  dynstr,  None ) ) ; 
275+         } 
276+     } 
277+ 
278+     let  soname = stub. add_dynamic_string ( soname. as_bytes ( ) ) ; 
234279
235280    // These initial reservations don't reserve any bytes in the binary yet, 
236281    // they just allocate in the internal data structures. 
237282
238-     // First, we crate  the dynamic symbol table. It starts with a null symbol 
283+     // First, we create  the dynamic symbol table. It starts with a null symbol 
239284    // and then all the symbols and their dynamic strings. 
240285    stub. reserve_null_dynamic_symbol_index ( ) ; 
241286
242-     let  dynstrs = symbols
243-         . iter ( ) 
244-         . map ( |sym| { 
245-             stub. reserve_dynamic_symbol_index ( ) ; 
246-             ( sym,  stub. add_dynamic_string ( sym. name . as_str ( ) . as_bytes ( ) ) ) 
247-         } ) 
248-         . collect :: < Vec < _ > > ( ) ; 
249- 
250-     let  soname = stub. add_dynamic_string ( soname. as_bytes ( ) ) ; 
287+     for  _ in  syms. iter ( )  { 
288+         stub. reserve_dynamic_symbol_index ( ) ; 
289+     } 
251290
252291    // Reserve the sections. 
253292    // We have the minimal sections for a dynamic SO and .text where we point our dummy symbols to. 
254293    stub. reserve_shstrtab_section_index ( ) ; 
255294    let  text_section_name = stub. add_section_name ( ".text" . as_bytes ( ) ) ; 
256295    let  text_section = stub. reserve_section_index ( ) ; 
257-     stub. reserve_dynstr_section_index ( ) ; 
258296    stub. reserve_dynsym_section_index ( ) ; 
297+     stub. reserve_dynstr_section_index ( ) ; 
298+     if  !vers. is_empty ( )  { 
299+         stub. reserve_gnu_versym_section_index ( ) ; 
300+         stub. reserve_gnu_verdef_section_index ( ) ; 
301+     } 
259302    stub. reserve_dynamic_section_index ( ) ; 
260303
261304    // These reservations now determine the actual layout order of the object file. 
262305    stub. reserve_file_header ( ) ; 
263306    stub. reserve_shstrtab ( ) ; 
264307    stub. reserve_section_headers ( ) ; 
265-     stub. reserve_dynstr ( ) ; 
266308    stub. reserve_dynsym ( ) ; 
309+     stub. reserve_dynstr ( ) ; 
310+     if  !vers. is_empty ( )  { 
311+         stub. reserve_gnu_versym ( ) ; 
312+         stub. reserve_gnu_verdef ( 1  + vers. len ( ) ,  1  + vers. len ( ) ) ; 
313+     } 
267314    stub. reserve_dynamic ( 2 ) ;  // DT_SONAME, DT_NULL 
268315
269316    // First write the ELF header with the arch information. 
270-     let  Some ( ( arch,  sub_arch) )  = sess. target . object_architecture ( & sess. unstable_target_features ) 
271-     else  { 
272-         sess. dcx ( ) . fatal ( format ! ( 
273-             "raw-dylib is not supported for the architecture `{}`" , 
274-             sess. target. arch
275-         ) ) ; 
276-     } ; 
277317    let  e_machine = match  ( arch,  sub_arch)  { 
278318        ( Architecture :: Aarch64 ,  None )  => elf:: EM_AARCH64 , 
279319        ( Architecture :: Aarch64_Ilp32 ,  None )  => elf:: EM_AARCH64 , 
@@ -342,18 +382,19 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
342382        sh_addralign :  1 , 
343383        sh_entsize :  0 , 
344384    } ) ; 
345-     stub. write_dynstr_section_header ( 0 ) ; 
346385    stub. write_dynsym_section_header ( 0 ,  1 ) ; 
386+     stub. write_dynstr_section_header ( 0 ) ; 
387+     if  !vers. is_empty ( )  { 
388+         stub. write_gnu_versym_section_header ( 0 ) ; 
389+         stub. write_gnu_verdef_section_header ( 0 ) ; 
390+     } 
347391    stub. write_dynamic_section_header ( 0 ) ; 
348392
349-     // .dynstr 
350-     stub. write_dynstr ( ) ; 
351- 
352393    // .dynsym 
353394    stub. write_null_dynamic_symbol ( ) ; 
354-     for  ( _ ,  name )  in  dynstrs  { 
395+     for  ( _name ,  dynstr ,  _ver )  in  syms . iter ( ) . copied ( )  { 
355396        stub. write_dynamic_symbol ( & write:: Sym  { 
356-             name :  Some ( name ) , 
397+             name :  Some ( dynstr ) , 
357398            st_info :  ( elf:: STB_GLOBAL  << 4 )  | elf:: STT_NOTYPE , 
358399            st_other :  elf:: STV_DEFAULT , 
359400            section :  Some ( text_section) , 
@@ -363,10 +404,47 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
363404        } ) ; 
364405    } 
365406
407+     // .dynstr 
408+     stub. write_dynstr ( ) ; 
409+ 
410+     // ld.bfd is unhappy if these sections exist without any symbols, so we only generate them when necessary. 
411+     if  !vers. is_empty ( )  { 
412+         // .gnu_version 
413+         stub. write_null_gnu_versym ( ) ; 
414+         for  ( _name,  _dynstr,  ver)  in  syms. iter ( ) . copied ( )  { 
415+             stub. write_gnu_versym ( if  let  Some ( ver)  = ver { 
416+                 assert ! ( ( 2  + ver as  u16 )  < elf:: VERSYM_HIDDEN ) ; 
417+                 elf:: VERSYM_HIDDEN  | ( 2  + ver as  u16 ) 
418+             }  else  { 
419+                 1 
420+             } ) ; 
421+         } 
422+ 
423+         // .gnu_version_d 
424+         stub. write_align_gnu_verdef ( ) ; 
425+         stub. write_gnu_verdef ( & write:: Verdef  { 
426+             version :  elf:: VER_DEF_CURRENT , 
427+             flags :  elf:: VER_FLG_BASE , 
428+             index :  1 , 
429+             aux_count :  1 , 
430+             name :  soname, 
431+         } ) ; 
432+         for  ( ver,  ( _name,  dynstr) )  in  vers. into_iter ( ) . enumerate ( )  { 
433+             stub. write_gnu_verdef ( & write:: Verdef  { 
434+                 version :  elf:: VER_DEF_CURRENT , 
435+                 flags :  0 , 
436+                 index :  2  + ver as  u16 , 
437+                 aux_count :  1 , 
438+                 name :  dynstr, 
439+             } ) ; 
440+         } 
441+     } 
442+ 
366443    // .dynamic 
367444    // the DT_SONAME will be used by the linker to populate DT_NEEDED 
368445    // which the loader uses to find the library. 
369446    // DT_NULL terminates the .dynamic table. 
447+     stub. write_align_dynamic ( ) ; 
370448    stub. write_dynamic_string ( elf:: DT_SONAME ,  soname) ; 
371449    stub. write_dynamic ( elf:: DT_NULL ,  0 ) ; 
372450
0 commit comments