@@ -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,67 @@ 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+ if !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+ }
256+ } else {
257+ let dynstr = stub. add_dynamic_string ( symbol_name. as_bytes ( ) ) ;
258+ syms. push ( ( symbol_name, dynstr, None ) ) ;
259+ }
260+ }
261+
262+ let soname = stub. add_dynamic_string ( soname. as_bytes ( ) ) ;
263+
235264 // These initial reservations don't reserve any bytes in the binary yet,
236265 // they just allocate in the internal data structures.
237266
238267 // First, we crate the dynamic symbol table. It starts with a null symbol
239268 // and then all the symbols and their dynamic strings.
240269 stub. reserve_null_dynamic_symbol_index ( ) ;
241270
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 ( ) ) ;
271+ for _ in syms. iter ( ) {
272+ stub. reserve_dynamic_symbol_index ( ) ;
273+ }
251274
252275 // Reserve the sections.
253276 // We have the minimal sections for a dynamic SO and .text where we point our dummy symbols to.
254277 stub. reserve_shstrtab_section_index ( ) ;
255278 let text_section_name = stub. add_section_name ( ".text" . as_bytes ( ) ) ;
256279 let text_section = stub. reserve_section_index ( ) ;
257- stub. reserve_dynstr_section_index ( ) ;
258280 stub. reserve_dynsym_section_index ( ) ;
281+ stub. reserve_dynstr_section_index ( ) ;
282+ stub. reserve_gnu_versym_section_index ( ) ;
283+ stub. reserve_gnu_verdef_section_index ( ) ;
259284 stub. reserve_dynamic_section_index ( ) ;
260285
261286 // These reservations now determine the actual layout order of the object file.
262287 stub. reserve_file_header ( ) ;
263288 stub. reserve_shstrtab ( ) ;
264289 stub. reserve_section_headers ( ) ;
265- stub. reserve_dynstr ( ) ;
266290 stub. reserve_dynsym ( ) ;
291+ stub. reserve_dynstr ( ) ;
292+ stub. reserve_gnu_versym ( ) ;
293+ stub. reserve_gnu_verdef ( 1 + vers. len ( ) , 1 + vers. len ( ) ) ;
267294 stub. reserve_dynamic ( 2 ) ; // DT_SONAME, DT_NULL
268295
269296 // First write the ELF header with the arch information.
@@ -342,18 +369,17 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
342369 sh_addralign : 1 ,
343370 sh_entsize : 0 ,
344371 } ) ;
345- stub. write_dynstr_section_header ( 0 ) ;
346372 stub. write_dynsym_section_header ( 0 , 1 ) ;
373+ stub. write_dynstr_section_header ( 0 ) ;
374+ stub. write_gnu_versym_section_header ( 0 ) ;
375+ stub. write_gnu_verdef_section_header ( 0 ) ;
347376 stub. write_dynamic_section_header ( 0 ) ;
348377
349- // .dynstr
350- stub. write_dynstr ( ) ;
351-
352378 // .dynsym
353379 stub. write_null_dynamic_symbol ( ) ;
354- for ( _ , name ) in dynstrs {
380+ for ( _name , dynstr , _ver ) in syms . iter ( ) . copied ( ) {
355381 stub. write_dynamic_symbol ( & write:: Sym {
356- name : Some ( name ) ,
382+ name : Some ( dynstr ) ,
357383 st_info : ( elf:: STB_GLOBAL << 4 ) | elf:: STT_NOTYPE ,
358384 st_other : elf:: STV_DEFAULT ,
359385 section : Some ( text_section) ,
@@ -363,10 +389,43 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
363389 } ) ;
364390 }
365391
392+ // .dynstr
393+ stub. write_dynstr ( ) ;
394+
395+ // .gnu_version
396+ stub. write_null_gnu_versym ( ) ;
397+ for ( _name, _dynstr, ver) in syms. iter ( ) . copied ( ) {
398+ stub. write_gnu_versym ( if let Some ( ver) = ver {
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