Skip to content

Commit 0bf3604

Browse files
committed
Add support for more than SHN_LORESERVE (0xff00) sections
1 parent f516c4d commit 0bf3604

File tree

4 files changed

+148
-18
lines changed

4 files changed

+148
-18
lines changed

src/LibObjectFile.Tests/Elf/ElfSimpleTests.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,5 +421,35 @@ public void TestAlignedSection()
421421

422422
Assert.AreEqual(alignedSection.UpperAlignment, codeSection.Offset, "Invalid alignment");
423423
}
424+
425+
[Test]
426+
public void TestManySections()
427+
{
428+
var elf = new ElfObjectFile(ElfArch.X86_64);
429+
430+
for (int i = 0; i < ushort.MaxValue; i++)
431+
{
432+
elf.AddSection(new ElfBinarySection { Name = $".section{i}" });
433+
}
434+
elf.AddSection(new ElfSectionHeaderStringTable());
435+
436+
var diagnostics = elf.Verify();
437+
Assert.False(diagnostics.HasErrors);
438+
439+
uint visibleSectionCount = elf.VisibleSectionCount;
440+
441+
using (var outStream = File.OpenWrite("manysections"))
442+
{
443+
elf.Write(outStream);
444+
outStream.Flush();
445+
}
446+
447+
using (var inStream = File.OpenRead("manysections"))
448+
{
449+
elf = ElfObjectFile.Read(inStream);
450+
}
451+
452+
Assert.AreEqual(visibleSectionCount, elf.VisibleSectionCount);
453+
}
424454
}
425455
}

src/LibObjectFile/Elf/ElfReader{TDecoder}.cs

Lines changed: 88 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System;
66
using System.Collections.Generic;
77
using System.IO;
8+
using static System.Collections.Specialized.BitVector32;
89

910
namespace 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)
214217
{
215-
var offset = Layout.OffsetOfSectionHeaderTable + (ulong)i * Layout.SizeOfSectionHeaderEntry;
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++)
231+
{
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,6 +317,68 @@ 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
{
@@ -609,7 +688,7 @@ private void VerifyAndFixProgramHeadersAndSections()
609688
}
610689
}
611690

612-
private ElfSection CreateElfSection(int sectionIndex, ElfSectionType sectionType, bool isNullSection)
691+
private ElfSection CreateElfSection(uint sectionIndex, ElfSectionType sectionType, bool isNullSection)
613692
{
614693
ElfSection section = null;
615694

src/LibObjectFile/Elf/ElfWriter{TEncoder}.cs

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,9 @@ private unsafe void WriteSectionHeader32()
155155
// entries for sections
156156
_encoder.Encode(out hdr.e_shoff, (uint)Layout.OffsetOfSectionHeaderTable);
157157
_encoder.Encode(out hdr.e_shentsize, Layout.SizeOfSectionHeaderEntry);
158-
_encoder.Encode(out hdr.e_shnum, (ushort)ObjectFile.VisibleSectionCount);
159-
_encoder.Encode(out hdr.e_shstrndx, (ushort)(ObjectFile.SectionHeaderStringTable?.SectionIndex ?? (ushort)0));
158+
_encoder.Encode(out hdr.e_shnum, ObjectFile.VisibleSectionCount >= ElfNative.SHN_LORESERVE ? (ushort)0 : (ushort)ObjectFile.VisibleSectionCount);
159+
uint shstrSectionIndex = ObjectFile.SectionHeaderStringTable?.SectionIndex ?? 0u;
160+
_encoder.Encode(out hdr.e_shstrndx, shstrSectionIndex >= ElfNative.SHN_LORESERVE ? (ushort)ElfNative.SHN_XINDEX : (ushort)shstrSectionIndex);
160161

161162
Write(hdr);
162163
}
@@ -181,11 +182,13 @@ private unsafe void WriteSectionHeader64()
181182
// entries for sections
182183
_encoder.Encode(out hdr.e_shoff, Layout.OffsetOfSectionHeaderTable);
183184
_encoder.Encode(out hdr.e_shentsize, (ushort)sizeof(Elf64_Shdr));
184-
_encoder.Encode(out hdr.e_shnum, (ushort)ObjectFile.VisibleSectionCount);
185-
_encoder.Encode(out hdr.e_shstrndx, (ushort)(ObjectFile.SectionHeaderStringTable?.SectionIndex ?? (ushort)0));
185+
_encoder.Encode(out hdr.e_shnum, ObjectFile.VisibleSectionCount >= ElfNative.SHN_LORESERVE ? (ushort)0 : (ushort)ObjectFile.VisibleSectionCount);
186+
uint shstrSectionIndex = ObjectFile.SectionHeaderStringTable?.SectionIndex ?? 0u;
187+
_encoder.Encode(out hdr.e_shstrndx, shstrSectionIndex >= ElfNative.SHN_LORESERVE ? (ushort)ElfNative.SHN_XINDEX : (ushort)shstrSectionIndex);
186188

187189
Write(hdr);
188190
}
191+
189192
private void CheckProgramHeaders()
190193
{
191194
if (ObjectFile.Segments.Count == 0)
@@ -268,8 +271,17 @@ private void WriteSectionTableEntry32(ElfSection section)
268271
_encoder.Encode(out shdr.sh_flags, (uint)section.Flags);
269272
_encoder.Encode(out shdr.sh_addr, (uint)section.VirtualAddress);
270273
_encoder.Encode(out shdr.sh_offset, (uint)section.Offset);
271-
_encoder.Encode(out shdr.sh_size, (uint)section.Size);
272-
_encoder.Encode(out shdr.sh_link, section.Link.GetIndex());
274+
if (section.Index == 0 && ObjectFile.VisibleSectionCount >= ElfNative.SHN_LORESERVE)
275+
{
276+
_encoder.Encode(out shdr.sh_size, ObjectFile.VisibleSectionCount);
277+
uint shstrSectionIndex = ObjectFile.SectionHeaderStringTable?.SectionIndex ?? 0u;
278+
_encoder.Encode(out shdr.sh_link, shstrSectionIndex >= ElfNative.SHN_LORESERVE ? shstrSectionIndex : 0);
279+
}
280+
else
281+
{
282+
_encoder.Encode(out shdr.sh_size, (uint)section.Size);
283+
_encoder.Encode(out shdr.sh_link, section.Link.GetIndex());
284+
}
273285
_encoder.Encode(out shdr.sh_info, section.Info.GetIndex());
274286
_encoder.Encode(out shdr.sh_addralign, (uint)section.Alignment);
275287
_encoder.Encode(out shdr.sh_entsize, (uint)section.TableEntrySize);
@@ -284,8 +296,17 @@ private void WriteSectionTableEntry64(ElfSection section)
284296
_encoder.Encode(out shdr.sh_flags, (uint)section.Flags);
285297
_encoder.Encode(out shdr.sh_addr, section.VirtualAddress);
286298
_encoder.Encode(out shdr.sh_offset, section.Offset);
287-
_encoder.Encode(out shdr.sh_size, section.Size);
288-
_encoder.Encode(out shdr.sh_link, section.Link.GetIndex());
299+
if (section.Index == 0 && ObjectFile.VisibleSectionCount >= ElfNative.SHN_LORESERVE)
300+
{
301+
_encoder.Encode(out shdr.sh_size, ObjectFile.VisibleSectionCount);
302+
uint shstrSectionIndex = ObjectFile.SectionHeaderStringTable?.SectionIndex ?? 0u;
303+
_encoder.Encode(out shdr.sh_link, shstrSectionIndex >= ElfNative.SHN_LORESERVE ? shstrSectionIndex : 0);
304+
}
305+
else
306+
{
307+
_encoder.Encode(out shdr.sh_size, section.Size);
308+
_encoder.Encode(out shdr.sh_link, section.Link.GetIndex());
309+
}
289310
_encoder.Encode(out shdr.sh_info, section.Info.GetIndex());
290311
_encoder.Encode(out shdr.sh_addralign, section.Alignment);
291312
_encoder.Encode(out shdr.sh_entsize, section.TableEntrySize);

src/LibObjectFile/Elf/Sections/ElfBinarySection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public override ElfSectionType Type
4242
}
4343

4444
public override ulong TableEntrySize => OriginalTableEntrySize;
45-
45+
4646
/// <summary>
4747
/// Gets or sets the associated stream to this section.
4848
/// </summary>

0 commit comments

Comments
 (0)