Skip to content

Commit 1746b62

Browse files
committed
Add support for symbol table referencing large section indexes
1 parent 9d69b89 commit 1746b62

6 files changed

Lines changed: 190 additions & 12 deletions

File tree

src/LibObjectFile.Tests/Elf/ElfSimpleTests.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,16 +426,33 @@ public void TestAlignedSection()
426426
public void TestManySections()
427427
{
428428
var elf = new ElfObjectFile(ElfArch.X86_64);
429+
var stringTable = new ElfStringTable();
430+
var symbolTable = new ElfSymbolTable { Link = stringTable };
429431

430432
for (int i = 0; i < ushort.MaxValue; i++)
431433
{
432-
elf.AddSection(new ElfBinarySection { Name = $".section{i}" });
434+
var section = new ElfBinarySection { Name = $".section{i}" };
435+
elf.AddSection(section);
436+
symbolTable.Entries.Add(new ElfSymbol { Type = ElfSymbolType.Section, Section = section });
433437
}
438+
439+
elf.AddSection(stringTable);
440+
elf.AddSection(symbolTable);
434441
elf.AddSection(new ElfSectionHeaderStringTable());
435442

436443
var diagnostics = elf.Verify();
444+
Assert.True(diagnostics.HasErrors);
445+
Assert.AreEqual(DiagnosticId.ELF_ERR_MissingSectionHeaderIndices, diagnostics.Messages[0].Id);
446+
447+
elf.AddSection(new ElfSymbolTableSectionHeaderIndices { Link = symbolTable });
448+
diagnostics = elf.Verify();
437449
Assert.False(diagnostics.HasErrors);
438450

451+
for (int i = 0; i < ushort.MaxValue; i++)
452+
{
453+
454+
}
455+
439456
uint visibleSectionCount = elf.VisibleSectionCount;
440457

441458
using (var outStream = File.OpenWrite("manysections"))

src/LibObjectFile/DiagnosticId.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ public enum DiagnosticId
6969
ELF_ERR_InvalidStreamForSectionNoBits = 156,
7070
ELF_ERR_InvalidNullSection = 157,
7171
ELF_ERR_InvalidAlignmentOutOfRange = 158,
72+
ELF_ERR_MissingSectionHeaderIndices = 159,
73+
ELF_ERR_MissingNullSection = 159,
7274

7375
AR_ERR_InvalidMagicLength = 1000,
7476
AR_ERR_MagicNotFound = 1001,

src/LibObjectFile/Elf/ElfObjectFile.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,12 @@ public override void Verify(DiagnosticBag diagnostics)
179179
diagnostics.Error(DiagnosticId.ELF_ERR_InvalidHeaderFileClassNone, $"Cannot compute the layout with an {nameof(ElfObjectFile)} having a {nameof(FileClass)} == {ElfFileClass.None}");
180180
}
181181

182+
if (VisibleSectionCount >= ElfNative.SHN_LORESERVE &&
183+
Sections[0] is not ElfNullSection)
184+
{
185+
diagnostics.Error(DiagnosticId.ELF_ERR_MissingNullSection, $"Section count is higher than SHN_LORESERVE ({ElfNative.SHN_LORESERVE}) but the first section is not a NULL section");
186+
}
187+
182188
foreach (var segment in Segments)
183189
{
184190
segment.Verify(diagnostics);

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

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ public override ElfSectionLink ResolveLink(ElfSectionLink link, string errorMess
385385
if (errorMessageFormat == null) throw new ArgumentNullException(nameof(errorMessageFormat));
386386

387387
// Connect section Link instance
388-
if (!link.IsSpecial)
388+
if (!link.IsEmpty)
389389
{
390390
if (link.SpecialIndex == _sectionStringTableIndex)
391391
{
@@ -396,13 +396,21 @@ public override ElfSectionLink ResolveLink(ElfSectionLink link, string errorMess
396396
var sectionIndex = link.SpecialIndex;
397397

398398
bool sectionFound = false;
399-
foreach (var section in ObjectFile.Sections)
399+
if (sectionIndex < ObjectFile.Sections.Count && ObjectFile.Sections[(int)sectionIndex].SectionIndex == sectionIndex)
400400
{
401-
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)
402407
{
403-
link = new ElfSectionLink(section);
404-
sectionFound = true;
405-
break;
408+
if (section.SectionIndex == sectionIndex)
409+
{
410+
link = new ElfSectionLink(section);
411+
sectionFound = true;
412+
break;
413+
}
406414
}
407415
}
408416

@@ -723,6 +731,9 @@ private ElfSection CreateElfSection(uint sectionIndex, ElfSectionType sectionTyp
723731
case ElfSectionType.Note:
724732
section = new ElfNoteTable();
725733
break;
734+
case ElfSectionType.SymbolTableSectionHeaderIndices:
735+
section = new ElfSymbolTableSectionHeaderIndices();
736+
break;
726737
}
727738

728739
// If the section is not a builtin section, try to offload to a delegate

src/LibObjectFile/Elf/Sections/ElfSymbolTable.cs

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@ private void Write32(ElfWriter writer)
149149
writer.Encode(out sym.st_size, (uint)entry.Size);
150150
sym.st_info = (byte)(((byte) entry.Bind << 4) | (byte) entry.Type);
151151
sym.st_other = (byte) ((byte) entry.Visibility & 3);
152-
writer.Encode(out sym.st_shndx, (ElfNative.Elf32_Half) entry.Section.GetIndex());
152+
var sectionIndex = entry.Section.GetIndex();
153+
writer.Encode(out sym.st_shndx, sectionIndex < ElfNative.SHN_LORESERVE || entry.Section.IsSpecial ? (ElfNative.Elf32_Half)sectionIndex : (ElfNative.Elf32_Half)ElfNative.SHN_XINDEX);
153154

154155
writer.Write(sym);
155156
}
@@ -169,7 +170,8 @@ private void Write64(ElfWriter writer)
169170
writer.Encode(out sym.st_size, entry.Size);
170171
sym.st_info = (byte)(((byte)entry.Bind << 4) | (byte)entry.Type);
171172
sym.st_other = (byte)((byte)entry.Visibility & 3);
172-
writer.Encode(out sym.st_shndx, (ElfNative.Elf64_Half)entry.Section.GetIndex());
173+
var sectionIndex = entry.Section.GetIndex();
174+
writer.Encode(out sym.st_shndx, sectionIndex < ElfNative.SHN_LORESERVE || entry.Section.IsSpecial ? (ElfNative.Elf64_Half)sectionIndex : (ElfNative.Elf64_Half)ElfNative.SHN_XINDEX);
173175

174176
writer.Write(sym);
175177
}
@@ -183,6 +185,7 @@ protected override void AfterRead(ElfReader reader)
183185
for (int i = 0; i < Entries.Count; i++)
184186
{
185187
var entry = Entries[i];
188+
186189
if (stringTable != null)
187190
{
188191
if (stringTable.TryResolve(entry.Name, out var newEntry))
@@ -195,7 +198,10 @@ protected override void AfterRead(ElfReader reader)
195198
}
196199
}
197200

198-
entry.Section = reader.ResolveLink(entry.Section, $"Invalid link section index {entry.Section.SpecialIndex} for symbol table entry [{i}] from symbol table section [{this}]");
201+
if (entry.Section.SpecialIndex < ElfNative.SHN_LORESERVE)
202+
{
203+
entry.Section = reader.ResolveLink(entry.Section, $"Invalid link section index {entry.Section.SpecialIndex} for symbol table entry [{i}] from symbol table section [{this}]");
204+
}
199205

200206
Entries[i] = entry;
201207
}
@@ -212,6 +218,7 @@ public override void Verify(DiagnosticBag diagnostics)
212218
}
213219

214220
bool isAllowingLocal = true;
221+
bool needsSectionHeaderIndices = false;
215222

216223
for (int i = 0; i < Entries.Count; i++)
217224
{
@@ -222,9 +229,14 @@ public override void Verify(DiagnosticBag diagnostics)
222229
diagnostics.Error(DiagnosticId.ELF_ERR_InvalidFirstSymbolEntryNonNull, $"Invalid entry #{i} in the {nameof(ElfSymbolTable)} section [{Index}]. The first entry must be null/undefined");
223230
}
224231

225-
if (entry.Section.Section != null && entry.Section.Section.Parent != Parent)
232+
if (entry.Section.Section != null)
226233
{
227-
diagnostics.Error(DiagnosticId.ELF_ERR_InvalidSymbolEntrySectionParent, $"Invalid section for the symbol entry #{i} in the {nameof(ElfSymbolTable)} section [{Index}]. The section of the entry `{entry}` must the same than this symbol table section");
234+
if (entry.Section.Section.Parent != Parent)
235+
{
236+
diagnostics.Error(DiagnosticId.ELF_ERR_InvalidSymbolEntrySectionParent, $"Invalid section for the symbol entry #{i} in the {nameof(ElfSymbolTable)} section [{Index}]. The section of the entry `{entry}` must the same than this symbol table section");
237+
}
238+
239+
needsSectionHeaderIndices |= entry.Section.GetIndex() >= ElfNative.SHN_LORESERVE;
228240
}
229241

230242
stringTable.ReserveString(entry.Name);
@@ -244,6 +256,24 @@ public override void Verify(DiagnosticBag diagnostics)
244256
isAllowingLocal = false;
245257
}
246258
}
259+
260+
if (needsSectionHeaderIndices)
261+
{
262+
bool foundSectionHeaderIndices = false;
263+
foreach (ElfSection otherSection in Parent.Sections)
264+
{
265+
if (otherSection is ElfSymbolTableSectionHeaderIndices && otherSection.Link.Section == this)
266+
{
267+
foundSectionHeaderIndices = true;
268+
break;
269+
}
270+
}
271+
272+
if (!foundSectionHeaderIndices)
273+
{
274+
diagnostics.Error(DiagnosticId.ELF_ERR_MissingSectionHeaderIndices, $"Symbol table [{Name.Value}] references section indexes higher than SHN_LORESERVE and accompanying {nameof(ElfSymbolTableSectionHeaderIndices)} section is missing");
275+
}
276+
}
247277
}
248278

249279
public override unsafe void UpdateLayout(DiagnosticBag diagnostics)
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright (c) Alexandre Mutel. All rights reserved.
2+
// This file is licensed under the BSD-Clause 2 license.
3+
// See the license.txt file in the project root for more information.
4+
5+
using System;
6+
using System.Collections.Generic;
7+
8+
namespace LibObjectFile.Elf
9+
{
10+
/// <summary>
11+
/// A section with the type <see cref="ElfSectionType.SymbolTableSectionHeaderIndices"/>
12+
/// </summary>
13+
public sealed class ElfSymbolTableSectionHeaderIndices : ElfSection
14+
{
15+
public const string DefaultName = ".symtab_shndx";
16+
17+
private readonly List<ElfSectionLink> _entries;
18+
19+
public ElfSymbolTableSectionHeaderIndices() : base(ElfSectionType.SymbolTableSectionHeaderIndices)
20+
{
21+
Name = DefaultName;
22+
_entries = new List<ElfSectionLink>();
23+
}
24+
25+
public override ElfSectionType Type
26+
{
27+
get => base.Type;
28+
set
29+
{
30+
if (value != ElfSectionType.SymbolTableSectionHeaderIndices)
31+
{
32+
throw new ArgumentException($"Invalid type `{Type}` of the section [{Index}] `{nameof(ElfSymbolTableSectionHeaderIndices)}`. Only `{ElfSectionType.SymbolTableSectionHeaderIndices}` is valid");
33+
}
34+
base.Type = value;
35+
}
36+
}
37+
38+
/// <summary>
39+
/// Gets a list of <see cref="ElfSectionLink"/> entries.
40+
/// </summary>
41+
public IReadOnlyList<ElfSectionLink> Entries => _entries;
42+
43+
public override unsafe ulong TableEntrySize => sizeof(uint);
44+
45+
protected override void Read(ElfReader reader)
46+
{
47+
var numberOfEntries = base.Size / TableEntrySize;
48+
_entries.Clear();
49+
_entries.Capacity = (int)numberOfEntries;
50+
for (ulong i = 0; i < numberOfEntries; i++)
51+
{
52+
_entries.Add(new ElfSectionLink(reader.ReadU32()));
53+
}
54+
}
55+
56+
protected override void Write(ElfWriter writer)
57+
{
58+
// Write all entries
59+
for (int i = 0; i < Entries.Count; i++)
60+
{
61+
writer.WriteU32(Entries[i].GetIndex());
62+
}
63+
}
64+
65+
protected override void AfterRead(ElfReader reader)
66+
{
67+
// Verify that the link is safe and configured as expected
68+
Link.TryGetSectionSafe<ElfSymbolTable>(nameof(ElfSymbolTableSectionHeaderIndices), nameof(Link), this, reader.Diagnostics, out var symbolTable, ElfSectionType.SymbolTable, ElfSectionType.DynamicLinkerSymbolTable);
69+
70+
for (int i = 0; i < _entries.Count; i++)
71+
{
72+
var entry = _entries[i];
73+
if (entry.SpecialIndex != 0)
74+
{
75+
entry = reader.ResolveLink(entry.Section, $"Invalid link section index {entry.SpecialIndex} for symbol table entry [{i}] from symbol table section [{this}]");
76+
_entries[i] = entry;
77+
78+
// Update the link in symbol table
79+
var symbolTableEntry = symbolTable.Entries[i];
80+
symbolTableEntry.Section = entry.Section;
81+
symbolTable.Entries[i] = symbolTableEntry;
82+
}
83+
}
84+
}
85+
86+
public override void Verify(DiagnosticBag diagnostics)
87+
{
88+
base.Verify(diagnostics);
89+
90+
// Verify that the link is safe and configured as expected
91+
if (!Link.TryGetSectionSafe<ElfSymbolTable>(nameof(ElfSymbolTableSectionHeaderIndices), nameof(Link), this, diagnostics, out var symbolTable, ElfSectionType.SymbolTable, ElfSectionType.DynamicLinkerSymbolTable))
92+
{
93+
return;
94+
}
95+
96+
for (int i = 0; i < _entries.Count; i++)
97+
{
98+
var entry = _entries[i];
99+
if (entry.SpecialIndex != 0 && entry.Section != null && entry.Section.Parent != Parent)
100+
{
101+
diagnostics.Error(DiagnosticId.ELF_ERR_InvalidSymbolEntrySectionParent, $"Invalid section for the symbol entry #{i} in the {nameof(ElfSymbolTable)} section [{Index}]");
102+
}
103+
}
104+
}
105+
106+
public override unsafe void UpdateLayout(DiagnosticBag diagnostics)
107+
{
108+
if (diagnostics == null) throw new ArgumentNullException(nameof(diagnostics));
109+
Size = Parent == null || Parent.FileClass == ElfFileClass.None ? 0 : (ulong)Entries.Count * sizeof(uint);
110+
}
111+
}
112+
}

0 commit comments

Comments
 (0)