1
1
import driver:: session;
2
2
import lib:: llvm:: llvm;
3
3
import middle:: trans;
4
+ import middle:: metadata;
5
+ import middle:: ty;
4
6
import std:: str;
5
7
import std:: fs;
8
+ import std:: vec;
9
+ import std:: option;
10
+ import option:: some;
11
+ import option:: none;
12
+ import std:: sha1:: sha1;
13
+ import std:: sort;
14
+ import trans:: crate_ctxt;
15
+ import front:: ast;
6
16
7
17
import lib:: llvm:: llvm:: ModuleRef ;
8
18
import lib:: llvm:: llvm:: ValueRef ;
@@ -49,7 +59,7 @@ fn link_intrinsics(session::session sess, ModuleRef llmod) {
49
59
50
60
auto linkres = llvm:: LLVMLinkModules ( llmod, llintrinsicsmod) ;
51
61
llvm:: LLVMDisposeModule ( llintrinsicsmod) ;
52
-
62
+
53
63
if ( linkres == False ) {
54
64
llvm_err ( sess, "couldn't link the module with the intrinsics" ) ;
55
65
fail;
@@ -58,7 +68,7 @@ fn link_intrinsics(session::session sess, ModuleRef llmod) {
58
68
59
69
mod write {
60
70
fn is_object_or_assembly_or_exe ( output_type ot) -> bool {
61
- if ( ( ot == output_type_assembly) ||
71
+ if ( ( ot == output_type_assembly) ||
62
72
( ot == output_type_object) ||
63
73
( ot == output_type_exe) ) {
64
74
ret true ;
@@ -218,3 +228,235 @@ mod write {
218
228
}
219
229
}
220
230
231
+ /*
232
+ * Name mangling and its relationship to metadata. This is complex. Read
233
+ * carefully.
234
+ *
235
+ * The semantic model of Rust linkage is, broadly, that "there's no global
236
+ * namespace" between crates. Our aim is to preserve the illusion of this
237
+ * model despite the fact that it's not *quite* possible to implement on
238
+ * modern linkers. We initially didn't use system linkers at all, but have
239
+ * been convinced of their utility.
240
+ *
241
+ * There are a few issues to handle:
242
+ *
243
+ * - Linkers operate on a flat namespace, so we have to flatten names.
244
+ * We do this using the C++ namespace-mangling technique. Foo::bar
245
+ * symbols and such.
246
+ *
247
+ * - Symbols with the same name but different types need to get different
248
+ * linkage-names. We do this by hashing a string-encoding of the type into
249
+ * a fixed-size (currently 16-byte hex) cryptographic hash function (CHF:
250
+ * we use SHA1) to "prevent collisions". This is not airtight but 16 hex
251
+ * digits on uniform probability means you're going to need 2**32 same-name
252
+ * symbols in the same process before you're even hitting birthday-paradox
253
+ * collision probability.
254
+ *
255
+ * - Symbols in dirrerent crates but with same names "within" the crate need
256
+ * to get different linkage-names.
257
+ *
258
+ * So here is what we do:
259
+ *
260
+ * - Separate the meta tags into two sets: exported and local. Only work with
261
+ * the exported ones when considering linkage.
262
+ *
263
+ * - Consider two exported tags as special (and madatory): name and vers.
264
+ * Every crate gets them; if it doesn't name them explicitly we infer them
265
+ * as basename(crate) and "0.1", respectively. Call these CNAME, CVERS.
266
+ *
267
+ * - Define CMETA as all the non-name, non-vers exported meta tags in the
268
+ * crate (in sorted order).
269
+ *
270
+ * - Define CMH as hash(CMETA).
271
+ *
272
+ * - Compile our crate to lib CNAME-CMH-CVERS.so
273
+ *
274
+ * - Define STH(sym) as hash(CNAME, CMH, type_str(sym))
275
+ *
276
+ * - Suffix a mangled sym with ::STH@CVERS, so that it is unique in the
277
+ * name, non-name metadata, and type sense, and versioned in the way
278
+ * system linkers understand.
279
+ *
280
+ */
281
+
282
+
283
+ iter crate_export_metas ( ast:: crate c) -> @ast:: meta_item {
284
+ for ( @ast: : crate_directive cdir in c. node . directives ) {
285
+ alt ( cdir. node ) {
286
+ case ( ast:: cdir_meta ( ?v, ?mis) ) {
287
+ if ( v == ast:: export_meta) {
288
+ for ( @ast:: meta_item mi in mis) {
289
+ put mi;
290
+ }
291
+ }
292
+ }
293
+ case ( _) { }
294
+ }
295
+ }
296
+ }
297
+ fn get_crate_meta( & session:: session sess,
298
+ & ast:: crate c, str k, str default,
299
+ bool warn_default) -> str {
300
+ let vec[ @ast:: meta_item] v = [ ] ;
301
+ for each ( @ast:: meta_item mi in crate_export_metas ( c) ) {
302
+ if ( mi. node . name == k) {
303
+ v += [ mi] ;
304
+ }
305
+ }
306
+ alt ( vec:: len ( v) ) {
307
+ case ( 0 u) {
308
+ if ( warn_default) {
309
+ sess. warn ( #fmt ( "missing meta '%s', using '%s' as default" ,
310
+ k, default) ) ;
311
+ }
312
+ ret default;
313
+ }
314
+ case ( 1 u) {
315
+ ret v. ( 0 ) . node . value ;
316
+ }
317
+ case ( _) {
318
+ sess. span_err ( v. ( 1 ) . span , #fmt ( "duplicate meta '%s'" , k) ) ;
319
+ }
320
+ }
321
+ }
322
+
323
+ // This calculates CMH as defined above
324
+ fn crate_meta_extras_hash ( sha1 sha, & ast:: crate crate) -> str {
325
+ fn lteq ( & @ast:: meta_item ma,
326
+ & @ast:: meta_item mb) -> bool {
327
+ ret ma. node . name <= mb. node . name ;
328
+ }
329
+
330
+ fn len_and_str ( & str s) -> str {
331
+ ret #fmt( "%u_%s" , str:: byte_len ( s) , s) ;
332
+ }
333
+
334
+ let vec[ mutable @ast:: meta_item] v = [ mutable] ;
335
+ for each ( @ast:: meta_item mi in crate_export_metas ( crate ) ) {
336
+ if ( mi. node . name != "name" &&
337
+ mi. node . name != "vers" ) {
338
+ v += [ mutable mi] ;
339
+ }
340
+ }
341
+ sort:: quick_sort ( lteq, v) ;
342
+ sha. reset ( ) ;
343
+ for ( @ast:: meta_item m in v) {
344
+ sha. input_str ( len_and_str ( m. node . name ) ) ;
345
+ sha. input_str ( len_and_str ( m. node . value ) ) ;
346
+ }
347
+ ret truncated_sha1_result ( sha) ;
348
+ }
349
+
350
+ fn crate_meta_name ( & session:: session sess, & ast:: crate crate,
351
+ & str output ) -> str {
352
+ auto os = str:: split ( fs:: basename ( output) , '.' as u8 ) ;
353
+ assert vec:: len ( os) >= 2 u;
354
+ vec:: pop ( os) ;
355
+ ret get_crate_meta ( sess, crate , "name" , str:: connect ( os, "." ) ,
356
+ sess. get_opts ( ) . shared ) ;
357
+ }
358
+
359
+ fn crate_meta_vers ( & session:: session sess, & ast:: crate crate) -> str {
360
+ ret get_crate_meta ( sess, crate , "vers" , "0.0" ,
361
+ sess. get_opts ( ) . shared ) ;
362
+ }
363
+
364
+ fn truncated_sha1_result ( sha1 sha) -> str {
365
+ ret str:: substr ( sha. result_str ( ) , 0 u, 16 u) ;
366
+ }
367
+
368
+
369
+
370
+ // This calculates STH for a symbol, as defined above
371
+ fn symbol_hash ( ty:: ctxt tcx, sha1 sha, & ty:: t t,
372
+ str crate_meta_name ,
373
+ str crate_meta_extras_hash ) -> str {
374
+ // NB: do *not* use abbrevs here as we want the symbol names
375
+ // to be independent of one another in the crate.
376
+ auto cx = @rec ( ds=metadata:: def_to_str, tcx=tcx,
377
+ abbrevs=metadata:: ac_no_abbrevs) ;
378
+ sha. reset ( ) ;
379
+ sha. input_str ( crate_meta_name) ;
380
+ sha. input_str ( "-" ) ;
381
+ sha. input_str ( crate_meta_name) ;
382
+ sha. input_str ( "-" ) ;
383
+ sha. input_str ( metadata:: Encode :: ty_str ( cx, t) ) ;
384
+ auto hash = truncated_sha1_result ( sha) ;
385
+ // Prefix with _ so that it never blends into adjacent digits
386
+ ret "_" + hash;
387
+ }
388
+
389
+ fn get_symbol_hash ( & @crate_ctxt ccx , & ty:: t t) -> str {
390
+ auto hash = "" ;
391
+ alt ( ccx. type_sha1s . find ( t) ) {
392
+ case ( some ( ?h) ) { hash = h; }
393
+ case ( none) {
394
+ hash = symbol_hash ( ccx. tcx , ccx. sha , t,
395
+ ccx. crate_meta_name ,
396
+ ccx. crate_meta_extras_hash ) ;
397
+ ccx. type_sha1s . insert ( t, hash) ;
398
+ }
399
+ }
400
+ ret hash;
401
+ }
402
+
403
+
404
+ fn mangle ( & vec[ str] ss ) -> str {
405
+
406
+ // Follow C++ namespace-mangling style
407
+
408
+ auto n = "_ZN" ; // Begin name-sequence.
409
+
410
+ for ( str s in ss) {
411
+ n += #fmt ( "%u%s" , str:: byte_len ( s) , s) ;
412
+ }
413
+
414
+ n += "E" ; // End name-sequence.
415
+ ret n;
416
+ }
417
+
418
+
419
+ fn exported_name ( & vec[ str] path , & str hash , & str vers ) -> str {
420
+ // FIXME: versioning isn't working yet
421
+ ret mangle ( path + [ hash] ) ; // + "@" + vers;
422
+ }
423
+
424
+ fn mangle_exported_name ( & @crate_ctxt ccx , & vec[ str] path ,
425
+ & ty:: t t) -> str {
426
+ auto hash = get_symbol_hash ( ccx, t) ;
427
+ ret exported_name ( path, hash, ccx. crate_meta_vers ) ;
428
+ }
429
+
430
+ fn mangle_internal_name_by_type_only ( & @crate_ctxt ccx , & ty:: t t,
431
+ & str name ) -> str {
432
+ auto f = metadata:: def_to_str;
433
+ auto cx = @rec ( ds=f, tcx=ccx. tcx , abbrevs=metadata:: ac_no_abbrevs) ;
434
+ auto s = ty:: ty_to_short_str ( ccx. tcx , t) ;
435
+
436
+ auto hash = get_symbol_hash ( ccx, t) ;
437
+ ret mangle( [ name, s, hash] ) ;
438
+ }
439
+
440
+ fn mangle_internal_name_by_path_and_seq ( & @crate_ctxt ccx , & vec[ str] path ,
441
+ & str flav ) -> str {
442
+ ret mangle ( path + [ ccx. names . next ( flav) ] ) ;
443
+ }
444
+
445
+ fn mangle_internal_name_by_path ( & @crate_ctxt ccx , & vec[ str] path ) -> str {
446
+ ret mangle ( path) ;
447
+ }
448
+
449
+ fn mangle_internal_name_by_seq ( & @crate_ctxt ccx , & str flav ) -> str {
450
+ ret ccx. names . next ( flav) ;
451
+ }
452
+
453
+ //
454
+ // Local Variables:
455
+ // mode: rust
456
+ // fill-column: 78;
457
+ // indent-tabs-mode: nil
458
+ // c-basic-offset: 4
459
+ // buffer-file-coding-system: utf-8-unix
460
+ // compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
461
+ // End:
462
+ //
0 commit comments