55using System ;
66using System . Collections . Generic ;
77using System . IO ;
8+ using static System . Collections . Specialized . BitVector32 ;
89
910namespace LibObjectFile . Elf
1011{
@@ -17,8 +18,8 @@ internal abstract class ElfReader<TDecoder> : ElfReader where TDecoder : struct,
1718 private TDecoder _decoder ;
1819 private ulong _startOfFile ;
1920 private ushort _programHeaderCount ;
20- private ushort _sectionHeaderCount ;
21- private ushort _sectionStringTableIndex ;
21+ private uint _sectionHeaderCount ;
22+ private uint _sectionStringTableIndex ;
2223 private bool _isFirstSectionValidNull ;
2324 private bool _hasValidSectionStringTable ;
2425
@@ -193,7 +194,7 @@ private ElfSegment ReadProgramHeader64(int phdrIndex)
193194
194195 private void ReadSections ( )
195196 {
196- if ( _sectionHeaderCount == 0 ) return ;
197+ if ( Layout . OffsetOfSectionHeaderTable == 0 ) return ;
197198
198199 // Write section header table
199200 ReadSectionHeaderTable ( ) ;
@@ -210,9 +211,25 @@ private void ReadSectionHeaderTable()
210211 return ;
211212 }
212213
213- for ( int i = 0 ; i < _sectionHeaderCount ; i ++ )
214+ uint i = 0 ;
215+
216+ if ( _sectionHeaderCount == 0 )
217+ {
218+ // We are dealing with an object file that has more than SHN_LORESERVE
219+ // (0xff00) sections. It has to begin with a NULL section header where
220+ // its Size contains the real number of sections, and Link optionally
221+ // points to string table section if it's section index is too high.
222+ if ( ReadExtendedNullSectionTableEntry ( ) )
223+ {
224+ i = 1 ;
225+ ObjectFile . AddSection ( new ElfNullSection ( ) ) ;
226+ _isFirstSectionValidNull = true ;
227+ }
228+ }
229+
230+ for ( ; i < _sectionHeaderCount ; i ++ )
214231 {
215- var offset = Layout . OffsetOfSectionHeaderTable + ( ulong ) i * Layout . SizeOfSectionHeaderEntry ;
232+ var offset = Layout . OffsetOfSectionHeaderTable + i * Layout . SizeOfSectionHeaderEntry ;
216233
217234 if ( offset >= ( ulong ) Stream . Length )
218235 {
@@ -228,12 +245,12 @@ private void ReadSectionHeaderTable()
228245 }
229246 }
230247
231- private ElfSection ReadSectionTableEntry ( int sectionIndex )
248+ private ElfSection ReadSectionTableEntry ( uint sectionIndex )
232249 {
233250 return ObjectFile . FileClass == ElfFileClass . Is32 ? ReadSectionTableEntry32 ( sectionIndex ) : ReadSectionTableEntry64 ( sectionIndex ) ;
234251 }
235252
236- private ElfSection ReadSectionTableEntry32 ( int sectionIndex )
253+ private ElfSection ReadSectionTableEntry32 ( uint sectionIndex )
237254 {
238255 var streamOffset = Stream . Position ;
239256 if ( ! TryReadData ( Layout . SizeOfSectionHeaderEntry , out ElfNative . Elf32_Shdr rawSection ) )
@@ -267,7 +284,7 @@ private ElfSection ReadSectionTableEntry32(int sectionIndex)
267284 return section ;
268285 }
269286
270- private ElfSection ReadSectionTableEntry64 ( int sectionIndex )
287+ private ElfSection ReadSectionTableEntry64 ( uint sectionIndex )
271288 {
272289 var streamOffset = Stream . Position ;
273290 if ( ! TryReadData ( Layout . SizeOfSectionHeaderEntry , out ElfNative . Elf64_Shdr rawSection ) )
@@ -300,13 +317,75 @@ private ElfSection ReadSectionTableEntry64(int sectionIndex)
300317
301318 return section ;
302319 }
320+
321+ private bool ReadExtendedNullSectionTableEntry ( )
322+ {
323+ uint sh_type ;
324+ ulong sh_size ;
325+ uint sh_link ;
326+ bool isNull ;
327+
328+ Stream . Position = ( long ) Layout . OffsetOfSectionHeaderTable ;
329+
330+ if ( ObjectFile . FileClass == ElfFileClass . Is32 )
331+ {
332+
333+ if ( ! TryReadData ( Layout . SizeOfSectionHeaderEntry , out ElfNative . Elf32_Shdr rawSection32 ) )
334+ {
335+ Diagnostics . Error ( DiagnosticId . ELF_ERR_IncompleteSectionHeader32Size , $ "Unable to read entirely NULL section header. Not enough data (size: { Layout . SizeOfSectionHeaderEntry } ) read at offset { Layout . OffsetOfSectionHeaderTable } from the stream") ;
336+ return false ;
337+ }
338+
339+ sh_type = _decoder . Decode ( rawSection32 . sh_type ) ;
340+ sh_size = _decoder . Decode ( rawSection32 . sh_size ) ;
341+ sh_link = _decoder . Decode ( rawSection32 . sh_link ) ;
342+ rawSection32 . sh_size = 0 ;
343+ rawSection32 . sh_link = 0 ;
344+ isNull = rawSection32 . IsNull ;
345+ }
346+ else
347+ {
348+ if ( ! TryReadData ( Layout . SizeOfSectionHeaderEntry , out ElfNative . Elf64_Shdr rawSection64 ) )
349+ {
350+ Diagnostics . Error ( DiagnosticId . ELF_ERR_IncompleteSectionHeader64Size , $ "Unable to read entirely NULL section header. Not enough data (size: { Layout . SizeOfSectionHeaderEntry } ) read at offset { Layout . OffsetOfSectionHeaderTable } from the stream") ;
351+ return false ;
352+ }
353+
354+ sh_type = _decoder . Decode ( rawSection64 . sh_type ) ;
355+ sh_size = _decoder . Decode ( rawSection64 . sh_size ) ;
356+ sh_link = _decoder . Decode ( rawSection64 . sh_link ) ;
357+ rawSection64 . sh_size = 0 ;
358+ rawSection64 . sh_link = 0 ;
359+ isNull = rawSection64 . IsNull ;
360+ }
361+
362+ if ( ! isNull )
363+ {
364+ Diagnostics . Error ( DiagnosticId . ELF_ERR_InvalidFirstSectionExpectingUndefined , $ "Invalid Section [0] { ( ElfSectionType ) sh_type } . Expecting { ElfNative . SHN_UNDEF } ") ;
365+ return false ;
366+ }
367+
368+ if ( sh_size >= uint . MaxValue )
369+ {
370+ Diagnostics . Error ( DiagnosticId . ELF_ERR_InvalidSectionHeaderCount , $ "Extended section count [{ sh_size } ] exceeds { uint . MaxValue } ") ;
371+ return false ;
372+ }
373+
374+ _sectionHeaderCount = ( uint ) sh_size ;
375+ if ( _sectionStringTableIndex == ElfNative . SHN_XINDEX )
376+ {
377+ _sectionStringTableIndex = sh_link ;
378+ }
379+
380+ return true ;
381+ }
303382
304383 public override ElfSectionLink ResolveLink ( ElfSectionLink link , string errorMessageFormat )
305384 {
306385 if ( errorMessageFormat == null ) throw new ArgumentNullException ( nameof ( errorMessageFormat ) ) ;
307386
308387 // Connect section Link instance
309- if ( ! link . IsSpecial )
388+ if ( ! link . IsEmpty )
310389 {
311390 if ( link . SpecialIndex == _sectionStringTableIndex )
312391 {
@@ -317,13 +396,21 @@ public override ElfSectionLink ResolveLink(ElfSectionLink link, string errorMess
317396 var sectionIndex = link . SpecialIndex ;
318397
319398 bool sectionFound = false ;
320- foreach ( var section in ObjectFile . Sections )
399+ if ( sectionIndex < ObjectFile . Sections . Count && ObjectFile . Sections [ ( int ) sectionIndex ] . SectionIndex == sectionIndex )
321400 {
322- if ( section . SectionIndex == sectionIndex )
401+ link = new ElfSectionLink ( ObjectFile . Sections [ ( int ) sectionIndex ] ) ;
402+ sectionFound = true ;
403+ }
404+ else
405+ {
406+ foreach ( var section in ObjectFile . Sections )
323407 {
324- link = new ElfSectionLink ( section ) ;
325- sectionFound = true ;
326- break ;
408+ if ( section . SectionIndex == sectionIndex )
409+ {
410+ link = new ElfSectionLink ( section ) ;
411+ sectionFound = true ;
412+ break ;
413+ }
327414 }
328415 }
329416
@@ -425,7 +512,7 @@ private void VerifyAndFixProgramHeadersAndSections()
425512 // Make sure to pre-sort all sections by offset
426513 var orderedSections = new List < ElfSection > ( ObjectFile . Sections . Count ) ;
427514 orderedSections . AddRange ( ObjectFile . Sections ) ;
428- orderedSections . Sort ( CompareSectionOffsetsDelegate ) ;
515+ orderedSections . Sort ( CompareSectionOffsetsAndSizesDelegate ) ;
429516 // Store the stream index to recover the same order when saving back.
430517 for ( int i = 0 ; i < orderedSections . Count ; i ++ )
431518 {
@@ -461,10 +548,10 @@ private void VerifyAndFixProgramHeadersAndSections()
461548 lastOffset = section . Offset + section . Size - 1 ;
462549
463550 // Verify overlapping sections and generate and error
464- for ( int j = i + 1 ; j < orderedSections . Count ; j ++ )
551+ if ( i + 1 < orderedSections . Count )
465552 {
466- var otherSection = orderedSections [ j ] ;
467- if ( section . Contains ( otherSection ) || otherSection . Contains ( section ) )
553+ var otherSection = orderedSections [ i + 1 ] ;
554+ if ( otherSection . Offset < section . Offset + section . Size )
468555 {
469556 Diagnostics . Warning ( DiagnosticId . ELF_ERR_InvalidOverlappingSections , $ "The section { section } [{ section . Offset } : { section . Offset + section . Size - 1 } ] is overlapping with the section { otherSection } [{ otherSection . Offset } : { otherSection . Offset + otherSection . Size - 1 } ]") ;
470557 }
@@ -609,7 +696,7 @@ private void VerifyAndFixProgramHeadersAndSections()
609696 }
610697 }
611698
612- private ElfSection CreateElfSection ( int sectionIndex , ElfSectionType sectionType , bool isNullSection )
699+ private ElfSection CreateElfSection ( uint sectionIndex , ElfSectionType sectionType , bool isNullSection )
613700 {
614701 ElfSection section = null ;
615702
@@ -644,6 +731,9 @@ private ElfSection CreateElfSection(int sectionIndex, ElfSectionType sectionType
644731 case ElfSectionType . Note :
645732 section = new ElfNoteTable ( ) ;
646733 break ;
734+ case ElfSectionType . SymbolTableSectionHeaderIndices :
735+ section = new ElfSymbolTableSectionHeaderIndices ( ) ;
736+ break ;
647737 }
648738
649739 // If the section is not a builtin section, try to offload to a delegate
@@ -754,11 +844,16 @@ public override ushort Decode(ElfNative.Elf64_Versym src)
754844 return _decoder . Decode ( src ) ;
755845 }
756846
757- private static readonly Comparison < ElfSection > CompareSectionOffsetsDelegate = new Comparison < ElfSection > ( CompareSectionOffsets ) ;
847+ private static readonly Comparison < ElfSection > CompareSectionOffsetsAndSizesDelegate = new Comparison < ElfSection > ( CompareSectionOffsetsAndSizes ) ;
758848
759- private static int CompareSectionOffsets ( ElfSection left , ElfSection right )
849+ private static int CompareSectionOffsetsAndSizes ( ElfSection left , ElfSection right )
760850 {
761- return left . Offset . CompareTo ( right . Offset ) ;
851+ int result = left . Offset . CompareTo ( right . Offset ) ;
852+ if ( result == 0 )
853+ {
854+ result = left . Size . CompareTo ( right . Size ) ;
855+ }
856+ return result ;
762857 }
763858 }
764859}
0 commit comments