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); // Make sure to pre-sort all sections by offset ObjectFile.SortSectionsByOffset(); // Lastly verify integrity of all sections for (var i = 0; i < ObjectFile.Sections.Count; i++) { var section = ObjectFile.Sections[i]; section.Verify(this.Diagnostics); if (section.Size > 0) { // Collect sections parts fileParts.Insert(new ElfFilePart(section)); } // Verify overlapping sections and generate and error for (int j = i + 1; j < ObjectFile.Sections.Count; j++) { var otherSection = ObjectFile.Sections[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}]"); } } } if (_isFirstSectionValidNull) { var programHeaderTable = new ElfProgramHeaderTable() { Offset = Layout.OffsetOfProgramHeaderTable, }; // Add the shadow section ElfProgramHeaderTable ObjectFile.InsertSectionAt(1, programHeaderTable); if (programHeaderTable.Size > 0) { fileParts.Insert(new ElfFilePart(programHeaderTable)); } } // Link segments to sections if we have an exact match. // otherwise record any segments that are not bound to a section. bool hasShadowSections = false; foreach (var segment in ObjectFile.Segments) { if (segment.Size == 0) { continue; } var segmentEndOffset = segment.Offset + segment.Size - 1; foreach (var section in ObjectFile.Sections) { if (section.Size == 0) { 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; segment.SizeKind = 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; uint previousSectionIndex = 1; // 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 ElfCustomShadowSection() { Name = ".shadow." + shadowCount, Offset = part.StartOffset, Size = part.EndOffset - part.StartOffset + 1 }; shadowCount++; Stream.Position = (long)shadowSection.Offset; shadowSection.ReadInternal(this); ObjectFile.InsertSectionAt((int)previousSectionIndex, shadowSection); fileParts[i] = new ElfFilePart(shadowSection); } else { previousSectionIndex = part.Section.Index + 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 < ObjectFile.Sections.Count; i++) { var section = ObjectFile.Sections[i]; if (section.Size == 0) { 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 < ObjectFile.Sections.Count; j++) { var nextSection = ObjectFile.Sections[j]; if (nextSection.Size == 0) { 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; segment.SizeKind = ValueKind.Auto; break; } } } } }