private void ReadSectionHeaderTable() { if (Layout.SizeOfSectionHeaderEntry == 0) { if (_sectionHeaderCount > 0) { Diagnostics.Error(DiagnosticId.ELF_ERR_InvalidZeroSectionHeaderTableEntrySize, $"Unable to read section header table as the size of section header entry ({nameof(ElfNative.Elf32_Ehdr.e_ehsize)}) == 0 in the Elf Header"); } return; } for (int i = 0; i < _sectionHeaderCount; i++) { var offset = Layout.OffsetOfSectionHeaderTable + (ulong)i * Layout.SizeOfSectionHeaderEntry; if (offset >= (ulong)Stream.Length) { Diagnostics.Error(DiagnosticId.ELF_ERR_InvalidSectionHeaderStreamOffset, $"Unable to read section [{i}] as its offset {offset} is out of bounds"); break; } // Seek to the header position Stream.Position = (long)offset; var section = ReadSectionTableEntry(i); ObjectFile.AddSection(section); } }
private void VerifyAndFixProgramHeadersAndSections() { if (!_isFirstSectionValidNull && ObjectFile.Sections.Count > 0) { Diagnostics.Error(DiagnosticId.ELF_ERR_InvalidFirstSectionExpectingUndefined, $"Invalid Section [0] {ObjectFile.Sections[0].Type}. Expecting {ElfNative.SHN_UNDEF}"); } if (_hasValidSectionStringTable) { Stream.Position = (long)ObjectFile.SectionHeaderStringTable.Offset; ObjectFile.SectionHeaderStringTable.ReadInternal(this); } for (var i = 0; i < ObjectFile.Sections.Count; i++) { var section = ObjectFile.Sections[i]; if (section is ElfNullSection || section is ElfProgramHeaderTable) { continue; } // Resolve the name of the section if (ObjectFile.SectionHeaderStringTable != null && ObjectFile.SectionHeaderStringTable.TryFind(section.Name.Index, out var sectionName)) { section.Name = section.Name.WithName(sectionName); } else { if (ObjectFile.SectionHeaderStringTable == null) { Diagnostics.Warning(DiagnosticId.ELF_ERR_InvalidStringIndexMissingStringHeaderTable, $"Unable to resolve string index [{section.Name.Index}] for section [{section.Index}] as section header string table does not exist"); } else { Diagnostics.Warning(DiagnosticId.ELF_ERR_InvalidStringIndex, $"Unable to resolve string index [{section.Name.Index}] for section [{section.Index}] from section header string table"); } } // Connect section Link instance section.Link = ResolveLink(section.Link, $"Invalid section Link [{{0}}] for section [{i}]"); // Connect section Info instance if (section.Type != ElfSectionType.DynamicLinkerSymbolTable && section.Type != ElfSectionType.SymbolTable) { section.Info = ResolveLink(section.Info, $"Invalid section Info [{{0}}] for section [{i}]"); } if (i == 0 && _isFirstSectionValidNull) { continue; } if (i == _sectionStringTableIndex && _hasValidSectionStringTable) { continue; } if (section.HasContent) { Stream.Position = (long)section.Offset; section.ReadInternal(this); } } foreach (var section in ObjectFile.Sections) { section.AfterReadInternal(this); } var fileParts = new ElfFilePartList(ObjectFile.Sections.Count + ObjectFile.Segments.Count); if (_isFirstSectionValidNull) { var programHeaderTable = new ElfProgramHeaderTable() { Offset = Layout.OffsetOfProgramHeaderTable, }; // Add the shadow section ElfProgramHeaderTable ObjectFile.InsertSectionAt(1, programHeaderTable); programHeaderTable.UpdateLayout(Diagnostics); if (programHeaderTable.Size > 0) { fileParts.Insert(new ElfFilePart(programHeaderTable)); } } // Make sure to pre-sort all sections by offset var orderedSections = new List <ElfSection>(ObjectFile.Sections.Count); orderedSections.AddRange(ObjectFile.Sections); orderedSections.Sort(CompareSectionOffsetsDelegate); // Store the stream index to recover the same order when saving back. for (int i = 0; i < orderedSections.Count; i++) { orderedSections[i].StreamIndex = (uint)i; } // Lastly verify integrity of all sections bool hasShadowSections = false; var lastOffset = fileParts.Count > 0 ? fileParts[fileParts.Count - 1].EndOffset : 0; for (var i = 0; i < orderedSections.Count; i++) { var section = orderedSections[i]; section.Verify(this.Diagnostics); if (lastOffset > 0 && section.Offset > lastOffset) { if (section.Offset > lastOffset) { // Create parts for the segment fileParts.CreateParts(lastOffset + 1, section.Offset - 1); hasShadowSections = true; } } if (section.Size == 0 || !section.HasContent) { continue; } // Collect sections parts fileParts.Insert(new ElfFilePart(section)); lastOffset = section.Offset + section.Size - 1; // Verify overlapping sections and generate and error for (int j = i + 1; j < orderedSections.Count; j++) { var otherSection = orderedSections[j]; if (section.Contains(otherSection) || otherSection.Contains(section)) { 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}]"); } } } // Link segments to sections if we have an exact match. // otherwise record any segments that are not bound to a section. foreach (var segment in ObjectFile.Segments) { if (segment.Size == 0) { continue; } var segmentEndOffset = segment.Offset + segment.Size - 1; foreach (var section in orderedSections) { if (section.Size == 0 || !section.HasContent) { continue; } var sectionEndOffset = section.Offset + section.Size - 1; if (segment.Offset == section.Offset && segmentEndOffset == sectionEndOffset) { // Single case: segment == section // If we found a section, we will bind the program header to this section // and switch the offset calculation to auto segment.Range = section; segment.OffsetKind = ValueKind.Auto; break; } } if (segment.Range.IsEmpty) { var offset = segment.Offset; // If a segment offset is set to 0, we need to take into // account the fact that the Elf header is already being handled // so we should not try to create a shadow section for it if (offset < Layout.SizeOfElfHeader) { offset = Layout.SizeOfElfHeader; } // Create parts for the segment fileParts.CreateParts(offset, segmentEndOffset); hasShadowSections = true; } } // If the previous loop has created ElfFilePart, we have to // create ElfCustomShadowSection and update the ElfSegment.Range if (hasShadowSections) { int shadowCount = 0; // If we have sections and the first section is NULL valid, we can start inserting // shadow sections at index 1 (after null section), otherwise we can insert shadow // sections before. uint previousSectionIndex = _isFirstSectionValidNull ? 1U : 0U; // Create ElfCustomShadowSection for any parts in the file // that are referenced by a segment but doesn't have a section for (var i = 0; i < fileParts.Count; i++) { var part = fileParts[i]; if (part.Section == null) { var shadowSection = new ElfBinaryShadowSection() { Name = ".shadow." + shadowCount, Offset = part.StartOffset, Size = part.EndOffset - part.StartOffset + 1 }; shadowCount++; Stream.Position = (long)shadowSection.Offset; shadowSection.ReadInternal(this); // Insert the shadow section with this order shadowSection.StreamIndex = previousSectionIndex; for (int j = (int)previousSectionIndex; j < orderedSections.Count; j++) { var otherSection = orderedSections[j]; otherSection.StreamIndex++; } // Update ordered sections orderedSections.Insert((int)previousSectionIndex, shadowSection); ObjectFile.AddSection(shadowSection); fileParts[i] = new ElfFilePart(shadowSection); } else { previousSectionIndex = part.Section.StreamIndex + 1; } } // Update all segment Ranges foreach (var segment in ObjectFile.Segments) { if (segment.Size == 0) { continue; } if (!segment.Range.IsEmpty) { continue; } var segmentEndOffset = segment.Offset + segment.Size - 1; for (var i = 0; i < orderedSections.Count; i++) { var section = orderedSections[i]; if (section.Size == 0 || !section.HasContent) { continue; } var sectionEndOffset = section.Offset + section.Size - 1; if (segment.Offset >= section.Offset && segment.Offset <= sectionEndOffset) { ElfSection beginSection = section; ElfSection endSection = null; for (int j = i; j < orderedSections.Count; j++) { var nextSection = orderedSections[j]; if (nextSection.Size == 0 || !nextSection.HasContent) { continue; } sectionEndOffset = nextSection.Offset + nextSection.Size - 1; if (segmentEndOffset >= nextSection.Offset && segmentEndOffset <= sectionEndOffset) { endSection = nextSection; break; } } if (endSection == null) { // TODO: is it a throw/assert or a log? Diagnostics.Error(DiagnosticId.ELF_ERR_InvalidSegmentRange, $"Invalid range for {segment}. The range is set to empty"); } else { segment.Range = new ElfSegmentRange(beginSection, segment.Offset - beginSection.Offset, endSection, (long)(segmentEndOffset - endSection.Offset)); } segment.OffsetKind = ValueKind.Auto; break; } } } } }