@@ -304,17 +304,7 @@ impl BytecodeObject {
304
304
/// See also: <https://docs.soliditylang.org/en/develop/using-the-compiler.html#library-linking>
305
305
pub fn link_fully_qualified ( & mut self , name : & str , addr : Address ) -> & mut Self {
306
306
if let Self :: Unlinked ( unlinked) = self {
307
- let place_holder = utils:: library_hash_placeholder ( name) ;
308
- // the address as hex without prefix
309
- let hex_addr = hex:: encode ( addr) ;
310
-
311
- // the library placeholder used to be the fully qualified name of the library instead of
312
- // the hash. This is also still supported by `solc` so we handle this as well
313
- let fully_qualified_placeholder = utils:: library_fully_qualified_placeholder ( name) ;
314
-
315
- * unlinked = unlinked
316
- . replace ( & format ! ( "__{fully_qualified_placeholder}__" ) , & hex_addr)
317
- . replace ( & format ! ( "__{place_holder}__" ) , & hex_addr)
307
+ link ( unlinked, name, addr) ;
318
308
}
319
309
self
320
310
}
@@ -386,6 +376,43 @@ impl AsRef<[u8]> for BytecodeObject {
386
376
}
387
377
}
388
378
379
+ /// Reference: <https://github.com/argotorg/solidity/blob/965166317bbc2b02067eb87f222a2dce9d24e289/libevmasm/LinkerObject.cpp#L38>
380
+ fn link ( unlinked : & mut String , name : & str , addr : Address ) {
381
+ const LEN : usize = 40 ;
382
+
383
+ let mut refs = vec ! [ ] ;
384
+ let mut find = |needle : & str | {
385
+ assert_eq ! ( needle. len( ) , LEN , "{needle:?}" ) ;
386
+ refs. extend ( memchr:: memmem:: find_iter ( unlinked. as_bytes ( ) , needle) ) ;
387
+ } ;
388
+
389
+ let placeholder = utils:: library_hash_placeholder ( name) ;
390
+ find ( & format ! ( "__{placeholder}__" ) ) ;
391
+
392
+ // The library placeholder used to be the fully qualified name of the library instead of
393
+ // the hash. This is also still supported by `solc` so we handle this as well.
394
+ let fully_qualified_placeholder = utils:: library_fully_qualified_placeholder ( name) ;
395
+ find ( & format ! ( "__{fully_qualified_placeholder}__" ) ) ;
396
+
397
+ if refs. is_empty ( ) {
398
+ debug ! ( "no references found while linking {name} -> {addr}" ) ;
399
+ return ;
400
+ }
401
+
402
+ // The address as hex without prefix.
403
+ let mut buffer = hex:: Buffer :: < 20 , false > :: new ( ) ;
404
+ let hex_addr = & * buffer. format ( & addr) ;
405
+ assert_eq ! ( hex_addr. len( ) , LEN , "{hex_addr:?}" ) ;
406
+
407
+ // The ranges are non-overlapping, so we don't need to sort, and can iterate in whatever order
408
+ // because of equal lengths.
409
+ // SAFETY: We're replacing LEN bytes at a time, and all the indexes come from the same string.
410
+ let unlinked = unsafe { unlinked. as_bytes_mut ( ) } ;
411
+ for & idx in & refs {
412
+ unlinked[ idx..idx + LEN ] . copy_from_slice ( hex_addr. as_bytes ( ) ) ;
413
+ }
414
+ }
415
+
389
416
/// This will serialize the bytecode data without a `0x` prefix, which the `ethers::types::Bytes`
390
417
/// adds by default.
391
418
///
0 commit comments