@@ -438,6 +438,131 @@ public async Task SimpleProgramHeaderAndCodeSectionAndSymbolSectionAndRelocation
438438 }
439439
440440
441+ [ TestMethod ]
442+ public async Task SimpleDynamicSection ( )
443+ {
444+ var elf = new ElfFile ( ElfArch . X86_64 ) ;
445+
446+ var dynstr = new ElfStringTable ( ) { Name = ".dynstr" } ;
447+ elf . Add ( dynstr ) ;
448+
449+ var dynamic = new ElfDynamicLinkingTable ( ) { Link = dynstr } ;
450+ dynamic . AddNeededLibrary ( "libc.so.6" ) ;
451+ dynamic . AddNeededLibrary ( "libm.so.6" ) ;
452+ dynamic . Entries . Add ( new ElfDynamic { Tag = ( long ) ElfDynamicTag . Flags1 , Value = 0x08000001 } ) ;
453+ dynamic . Entries . Add ( new ElfDynamic { Tag = ( long ) ElfDynamicTag . Null } ) ;
454+ elf . Add ( dynamic ) ;
455+
456+ elf . Add ( new ElfSectionHeaderStringTable ( ) ) ;
457+ elf . Add ( new ElfSectionHeaderTable ( ) ) ;
458+
459+ // The read helpers resolve DT_NEEDED offsets through the linked .dynstr.
460+ CollectionAssert . AreEqual ( new [ ] { "libc.so.6" , "libm.so.6" } , dynamic . GetNeededLibraries ( ) . ToList ( ) ) ;
461+
462+ await AssertReadElf ( elf , "test_dynamic.elf" ) ;
463+
464+ // Round-trip the entries and confirm the resolved library names survive write -> read.
465+ var memoryStream = new MemoryStream ( ) ;
466+ elf . Write ( memoryStream ) ;
467+ memoryStream . Position = 0 ;
468+ var roundTrip = ElfFile . Read ( memoryStream ) ;
469+ var roundTripDynamic = roundTrip . Sections . OfType < ElfDynamicLinkingTable > ( ) . Single ( ) ;
470+ Assert . AreEqual ( dynamic . Entries . Count , roundTripDynamic . Entries . Count ) ;
471+ CollectionAssert . AreEqual ( new [ ] { "libc.so.6" , "libm.so.6" } , roundTripDynamic . GetNeededLibraries ( ) . ToList ( ) ) ;
472+ }
473+
474+ [ TestMethod ]
475+ public void DynamicSectionStreamRoundTrip ( )
476+ {
477+ var elf = new ElfFile ( ElfArch . X86_64 ) ;
478+ var dynstr = new ElfStringTable ( ) { Name = ".dynstr" } ;
479+ elf . Add ( dynstr ) ;
480+
481+ var dynamic = new ElfDynamicLinkingTable ( ) { Link = dynstr } ;
482+ dynamic . AddNeededLibrary ( "libc.so.6" ) ;
483+ dynamic . Entries . Add ( new ElfDynamic { Tag = ( long ) ElfDynamicTag . Flags1 , Value = 0x08000001 } ) ;
484+ dynamic . Entries . Add ( new ElfDynamic { Tag = ( long ) ElfDynamicTag . Null } ) ;
485+ elf . Add ( dynamic ) ;
486+
487+ // Serialize just the .dynamic entries to a standalone stream (64-bit -> 16 bytes each).
488+ var stream = new MemoryStream ( ) ;
489+ dynamic . Write ( stream ) ;
490+ Assert . AreEqual ( dynamic . Entries . Count * 16 , stream . Length ) ;
491+
492+ // Read them back into a fresh table attached to another file and confirm value equality.
493+ var elf2 = new ElfFile ( ElfArch . X86_64 ) ;
494+ var dynamic2 = new ElfDynamicLinkingTable ( ) ;
495+ elf2 . Add ( dynamic2 ) ;
496+ stream . Position = 0 ;
497+ dynamic2 . Read ( stream ) ;
498+
499+ CollectionAssert . AreEqual ( dynamic . Entries , dynamic2 . Entries ) ;
500+ }
501+
502+ [ TestMethod ]
503+ public void DynamicSection32Bit ( )
504+ {
505+ var elf = new ElfFile ( ElfArch . I386 ) ;
506+ var dynstr = new ElfStringTable ( ) { Name = ".dynstr" } ;
507+ elf . Add ( dynstr ) ;
508+
509+ var dynamic = new ElfDynamicLinkingTable ( ) { Link = dynstr } ;
510+ dynamic . AddNeededLibrary ( "libc.so.6" ) ;
511+ dynamic . Entries . Add ( new ElfDynamic { Tag = ( long ) ElfDynamicTag . Flags , Value = 0x8 } ) ; // DF_BIND_NOW
512+ dynamic . Entries . Add ( new ElfDynamic { Tag = ( long ) ElfDynamicTag . Null } ) ;
513+ elf . Add ( dynamic ) ;
514+
515+ // The printer uses 8-digit tag hex for 32-bit files.
516+ var writer = new StringWriter ( ) ;
517+ ElfPrinter . PrintDynamicSections ( elf , writer ) ;
518+ var text = writer . ToString ( ) ;
519+ StringAssert . Contains ( text , " 0x00000001 (NEEDED)" ) ;
520+ StringAssert . Contains ( text , "Shared library: [libc.so.6]" ) ;
521+ StringAssert . Contains ( text , " 0x0000001e (FLAGS)" ) ;
522+ StringAssert . Contains ( text , "BIND_NOW" ) ;
523+
524+ // The Read32/Write32 path uses 8-byte Elf32_Dyn records.
525+ var stream = new MemoryStream ( ) ;
526+ dynamic . Write ( stream ) ;
527+ Assert . AreEqual ( dynamic . Entries . Count * 8 , stream . Length ) ;
528+
529+ var elf2 = new ElfFile ( ElfArch . I386 ) ;
530+ var dynamic2 = new ElfDynamicLinkingTable ( ) ;
531+ elf2 . Add ( dynamic2 ) ;
532+ stream . Position = 0 ;
533+ dynamic2 . Read ( stream ) ;
534+
535+ CollectionAssert . AreEqual ( dynamic . Entries , dynamic2 . Entries ) ;
536+ }
537+
538+ [ TestMethod ]
539+ public void SectionHeader64BitFieldsNotTruncated ( )
540+ {
541+ // Regression: the 64-bit section header writer cast sh_addr/sh_offset/sh_size/etc. to uint,
542+ // truncating any value >= 4 GiB. A NOBITS section declares a huge address/size with no file bytes.
543+ var elf = new ElfFile ( ElfArch . X86_64 ) ;
544+
545+ var bss = new ElfNoBitsSection
546+ {
547+ Name = ".hugebss" ,
548+ VirtualAddress = 0x1_0000_2000UL , // > 4 GiB
549+ Size = 0x2_0000_1000UL , // > 4 GiB
550+ VirtualAddressAlignment = 0x1000 ,
551+ } ;
552+ elf . Add ( bss ) ;
553+ elf . Add ( new ElfSectionHeaderStringTable ( ) ) ;
554+ elf . Add ( new ElfSectionHeaderTable ( ) ) ;
555+
556+ var stream = new MemoryStream ( ) ;
557+ elf . Write ( stream ) ;
558+ stream . Position = 0 ;
559+ var roundTrip = ElfFile . Read ( stream ) ;
560+
561+ var bss2 = roundTrip . Sections . OfType < ElfNoBitsSection > ( ) . Single ( ) ;
562+ Assert . AreEqual ( 0x1_0000_2000UL , bss2 . VirtualAddress ) ;
563+ Assert . AreEqual ( 0x2_0000_1000UL , bss2 . Size ) ;
564+ }
565+
441566 [ TestMethod ]
442567 public async Task TestAlignedSection ( )
443568 {
0 commit comments