@@ -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 ; 
@@ -230,40 +230,66 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
230230        Endian :: Little  => object:: Endianness :: Little , 
231231        Endian :: Big  => object:: Endianness :: Big , 
232232    } ; 
233+ 
233234    let  mut  stub = write:: Writer :: new ( endianness,  true ,  & mut  stub_buf) ; 
234235
236+     let  mut  vers = Vec :: new ( ) ; 
237+     let  mut  vers_map = FxHashMap :: default ( ) ; 
238+     let  mut  syms = Vec :: new ( ) ; 
239+ 
240+     for  symbol in  symbols { 
241+         let  symbol_name = symbol. name . as_str ( ) ; 
242+         if  let  Some ( ( name,  version_name) )  = symbol_name. split_once ( '@' )  { 
243+             assert ! ( !version_name. contains( '@' ) ) ; 
244+             let  dynstr = stub. add_dynamic_string ( name. as_bytes ( ) ) ; 
245+             let  ver = if  let  Some ( & ver_id)  = vers_map. get ( version_name)  { 
246+                 ver_id
247+             }  else  { 
248+                 let  id = vers. len ( ) ; 
249+                 vers_map. insert ( version_name,  id) ; 
250+                 let  dynstr = stub. add_dynamic_string ( version_name. as_bytes ( ) ) ; 
251+                 vers. push ( ( version_name,  dynstr) ) ; 
252+                 id
253+             } ; 
254+             syms. push ( ( name,  dynstr,  Some ( ver) ) ) ; 
255+         }  else  { 
256+             let  dynstr = stub. add_dynamic_string ( symbol_name. as_bytes ( ) ) ; 
257+             syms. push ( ( symbol_name,  dynstr,  None ) ) ; 
258+         } 
259+     } 
260+ 
261+     let  soname = stub. add_dynamic_string ( soname. as_bytes ( ) ) ; 
262+ 
235263    // These initial reservations don't reserve any bytes in the binary yet, 
236264    // they just allocate in the internal data structures. 
237265
238266    // First, we crate the dynamic symbol table. It starts with a null symbol 
239267    // and then all the symbols and their dynamic strings. 
240268    stub. reserve_null_dynamic_symbol_index ( ) ; 
241269
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 ( ) ) ; 
270+     for  _ in  syms. iter ( )  { 
271+         stub. reserve_dynamic_symbol_index ( ) ; 
272+     } 
251273
252274    // Reserve the sections. 
253275    // We have the minimal sections for a dynamic SO and .text where we point our dummy symbols to. 
254276    stub. reserve_shstrtab_section_index ( ) ; 
255277    let  text_section_name = stub. add_section_name ( ".text" . as_bytes ( ) ) ; 
256278    let  text_section = stub. reserve_section_index ( ) ; 
257-     stub. reserve_dynstr_section_index ( ) ; 
258279    stub. reserve_dynsym_section_index ( ) ; 
280+     stub. reserve_dynstr_section_index ( ) ; 
281+     stub. reserve_gnu_versym_section_index ( ) ; 
282+     stub. reserve_gnu_verdef_section_index ( ) ; 
259283    stub. reserve_dynamic_section_index ( ) ; 
260284
261285    // These reservations now determine the actual layout order of the object file. 
262286    stub. reserve_file_header ( ) ; 
263287    stub. reserve_shstrtab ( ) ; 
264288    stub. reserve_section_headers ( ) ; 
265-     stub. reserve_dynstr ( ) ; 
266289    stub. reserve_dynsym ( ) ; 
290+     stub. reserve_dynstr ( ) ; 
291+     stub. reserve_gnu_versym ( ) ; 
292+     stub. reserve_gnu_verdef ( 1  + vers. len ( ) ,  1  + vers. len ( ) ) ; 
267293    stub. reserve_dynamic ( 2 ) ;  // DT_SONAME, DT_NULL 
268294
269295    // First write the ELF header with the arch information. 
@@ -342,18 +368,17 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
342368        sh_addralign :  1 , 
343369        sh_entsize :  0 , 
344370    } ) ; 
345-     stub. write_dynstr_section_header ( 0 ) ; 
346371    stub. write_dynsym_section_header ( 0 ,  1 ) ; 
372+     stub. write_dynstr_section_header ( 0 ) ; 
373+     stub. write_gnu_versym_section_header ( 0 ) ; 
374+     stub. write_gnu_verdef_section_header ( 0 ) ; 
347375    stub. write_dynamic_section_header ( 0 ) ; 
348376
349-     // .dynstr 
350-     stub. write_dynstr ( ) ; 
351- 
352377    // .dynsym 
353378    stub. write_null_dynamic_symbol ( ) ; 
354-     for  ( _ ,  name )  in  dynstrs  { 
379+     for  ( _name ,  dynstr ,  _ver )  in  syms . iter ( ) . copied ( )  { 
355380        stub. write_dynamic_symbol ( & write:: Sym  { 
356-             name :  Some ( name ) , 
381+             name :  Some ( dynstr ) , 
357382            st_info :  ( elf:: STB_GLOBAL  << 4 )  | elf:: STT_NOTYPE , 
358383            st_other :  elf:: STV_DEFAULT , 
359384            section :  Some ( text_section) , 
@@ -363,10 +388,44 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
363388        } ) ; 
364389    } 
365390
391+     // .dynstr 
392+     stub. write_dynstr ( ) ; 
393+ 
394+     // .gnu_version 
395+     stub. write_null_gnu_versym ( ) ; 
396+     for  ( _name,  _dynstr,  ver)  in  syms. iter ( ) . copied ( )  { 
397+         stub. write_gnu_versym ( if  let  Some ( ver)  = ver { 
398+             assert ! ( ( 2  + ver as  u16 )  < elf:: VERSYM_HIDDEN ) ; 
399+             elf:: VERSYM_HIDDEN  | ( 2  + ver as  u16 ) 
400+         }  else  { 
401+             1 
402+         } ) ; 
403+     } 
404+ 
405+     // .gnu_version_d 
406+     stub. write_align_gnu_verdef ( ) ; 
407+     stub. write_gnu_verdef ( & write:: Verdef  { 
408+         version :  elf:: VER_DEF_CURRENT , 
409+         flags :  elf:: VER_FLG_BASE , 
410+         index :  1 , 
411+         aux_count :  1 , 
412+         name :  soname, 
413+     } ) ; 
414+     for  ( ver,  ( _name,  dynstr) )  in  vers. into_iter ( ) . enumerate ( )  { 
415+         stub. write_gnu_verdef ( & write:: Verdef  { 
416+             version :  elf:: VER_DEF_CURRENT , 
417+             flags :  0 , 
418+             index :  2  + ver as  u16 , 
419+             aux_count :  1 , 
420+             name :  dynstr, 
421+         } ) ; 
422+     } 
423+ 
366424    // .dynamic 
367425    // the DT_SONAME will be used by the linker to populate DT_NEEDED 
368426    // which the loader uses to find the library. 
369427    // DT_NULL terminates the .dynamic table. 
428+     stub. write_align_dynamic ( ) ; 
370429    stub. write_dynamic_string ( elf:: DT_SONAME ,  soname) ; 
371430    stub. write_dynamic ( elf:: DT_NULL ,  0 ) ; 
372431
0 commit comments