@@ -4,7 +4,7 @@ use std::path::{Path, PathBuf};
4
4
5
5
use rustc_abi:: Endian ;
6
6
use rustc_data_structures:: base_n:: { CASE_INSENSITIVE , ToBaseN } ;
7
- use rustc_data_structures:: fx:: FxIndexMap ;
7
+ use rustc_data_structures:: fx:: { FxHashMap , FxIndexMap } ;
8
8
use rustc_data_structures:: stable_hasher:: StableHasher ;
9
9
use rustc_hashes:: Hash128 ;
10
10
use rustc_session:: Session ;
@@ -214,7 +214,7 @@ pub(super) fn create_raw_dylib_elf_stub_shared_objects<'a>(
214
214
/// It exports all the provided symbols, but is otherwise empty.
215
215
fn create_elf_raw_dylib_stub ( sess : & Session , soname : & str , symbols : & [ DllImport ] ) -> Vec < u8 > {
216
216
use object:: write:: elf as write;
217
- use object:: { Architecture , elf} ;
217
+ use object:: { AddressSize , Architecture , elf} ;
218
218
219
219
let mut stub_buf = Vec :: new ( ) ;
220
220
@@ -226,54 +226,94 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
226
226
// It is important that the order of reservation matches the order of writing.
227
227
// The object crate contains many debug asserts that fire if you get this wrong.
228
228
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
+
229
237
let endianness = match sess. target . options . endian {
230
238
Endian :: Little => object:: Endianness :: Little ,
231
239
Endian :: Big => object:: Endianness :: Big ,
232
240
} ;
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 ( ) ) ;
234
279
235
280
// These initial reservations don't reserve any bytes in the binary yet,
236
281
// they just allocate in the internal data structures.
237
282
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
239
284
// and then all the symbols and their dynamic strings.
240
285
stub. reserve_null_dynamic_symbol_index ( ) ;
241
286
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
+ }
251
290
252
291
// Reserve the sections.
253
292
// We have the minimal sections for a dynamic SO and .text where we point our dummy symbols to.
254
293
stub. reserve_shstrtab_section_index ( ) ;
255
294
let text_section_name = stub. add_section_name ( ".text" . as_bytes ( ) ) ;
256
295
let text_section = stub. reserve_section_index ( ) ;
257
- stub. reserve_dynstr_section_index ( ) ;
258
296
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
+ }
259
302
stub. reserve_dynamic_section_index ( ) ;
260
303
261
304
// These reservations now determine the actual layout order of the object file.
262
305
stub. reserve_file_header ( ) ;
263
306
stub. reserve_shstrtab ( ) ;
264
307
stub. reserve_section_headers ( ) ;
265
- stub. reserve_dynstr ( ) ;
266
308
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
+ }
267
314
stub. reserve_dynamic ( 2 ) ; // DT_SONAME, DT_NULL
268
315
269
316
// 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
- } ;
277
317
let e_machine = match ( arch, sub_arch) {
278
318
( Architecture :: Aarch64 , None ) => elf:: EM_AARCH64 ,
279
319
( Architecture :: Aarch64_Ilp32 , None ) => elf:: EM_AARCH64 ,
@@ -342,18 +382,19 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
342
382
sh_addralign : 1 ,
343
383
sh_entsize : 0 ,
344
384
} ) ;
345
- stub. write_dynstr_section_header ( 0 ) ;
346
385
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
+ }
347
391
stub. write_dynamic_section_header ( 0 ) ;
348
392
349
- // .dynstr
350
- stub. write_dynstr ( ) ;
351
-
352
393
// .dynsym
353
394
stub. write_null_dynamic_symbol ( ) ;
354
- for ( _ , name ) in dynstrs {
395
+ for ( _name , dynstr , _ver ) in syms . iter ( ) . copied ( ) {
355
396
stub. write_dynamic_symbol ( & write:: Sym {
356
- name : Some ( name ) ,
397
+ name : Some ( dynstr ) ,
357
398
st_info : ( elf:: STB_GLOBAL << 4 ) | elf:: STT_NOTYPE ,
358
399
st_other : elf:: STV_DEFAULT ,
359
400
section : Some ( text_section) ,
@@ -363,10 +404,47 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
363
404
} ) ;
364
405
}
365
406
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
+
366
443
// .dynamic
367
444
// the DT_SONAME will be used by the linker to populate DT_NEEDED
368
445
// which the loader uses to find the library.
369
446
// DT_NULL terminates the .dynamic table.
447
+ stub. write_align_dynamic ( ) ;
370
448
stub. write_dynamic_string ( elf:: DT_SONAME , soname) ;
371
449
stub. write_dynamic ( elf:: DT_NULL , 0 ) ;
372
450
0 commit comments