mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
Switch to a visitor-based no-alloc implementation for fetching ELF sections
This change is required as the code to create a new PDT should execute before the Go allocator is bootstrapped.
This commit is contained in:
parent
fdd5611220
commit
a2d58f8949
@ -7,9 +7,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
infoData uintptr
|
infoData uintptr
|
||||||
cmdLineKV map[string]string
|
cmdLineKV map[string]string
|
||||||
elfSectionList []*ElfSection
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type tagType uint32
|
type tagType uint32
|
||||||
@ -149,7 +148,7 @@ const (
|
|||||||
// MemRegionVisitor defies a visitor function that gets invoked by VisitMemRegions
|
// MemRegionVisitor defies a visitor function that gets invoked by VisitMemRegions
|
||||||
// for each memory region provided by the boot loader. The visitor must return true
|
// for each memory region provided by the boot loader. The visitor must return true
|
||||||
// to continue or false to abort the scan.
|
// to continue or false to abort the scan.
|
||||||
type MemRegionVisitor func(entry *MemoryMapEntry) bool
|
type MemRegionVisitor func(*MemoryMapEntry) bool
|
||||||
|
|
||||||
// MemoryMapEntry describes a memory region entry, namely its physical address,
|
// MemoryMapEntry describes a memory region entry, namely its physical address,
|
||||||
// its length and its type.
|
// its length and its type.
|
||||||
@ -230,63 +229,44 @@ const (
|
|||||||
ElfSectionExecutable
|
ElfSectionExecutable
|
||||||
)
|
)
|
||||||
|
|
||||||
// ElfSection deefines the name, flags and virtual address of an ELF section
|
// ElfSectionVisitor defies a visitor function that gets invoked by VisitElfSections
|
||||||
// which is part of the kernel image.
|
// for rach ELF section that belongs to the loaded kernel image.
|
||||||
type ElfSection struct {
|
type ElfSectionVisitor func(name string, flags ElfSectionFlag, address uintptr, size uint64)
|
||||||
// The section name.
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// The list of flags associated with this section
|
|
||||||
Flags ElfSectionFlag
|
|
||||||
|
|
||||||
// The virtual address of this section.
|
|
||||||
Address uintptr
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetElfSections returns a slice of ElfSections for the loaded kernel image.
|
|
||||||
func GetElfSections() []*ElfSection {
|
|
||||||
if elfSectionList != nil {
|
|
||||||
return elfSectionList
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// VisitElfSections invokes visitor for each ELF entry that belongs to the
|
||||||
|
// loaded kernel image.
|
||||||
|
func VisitElfSections(visitor ElfSectionVisitor) {
|
||||||
curPtr, size := findTagByType(tagElfSymbols)
|
curPtr, size := findTagByType(tagElfSymbols)
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ptrElfSections := (*elfSections)(unsafe.Pointer(curPtr))
|
|
||||||
sectionData := *(*[]elfSection64)(unsafe.Pointer(&reflect.SliceHeader{
|
|
||||||
Len: int(ptrElfSections.numSections),
|
|
||||||
Cap: int(ptrElfSections.numSections),
|
|
||||||
Data: uintptr(unsafe.Pointer(&ptrElfSections.sectionData)),
|
|
||||||
}))
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
strTable = *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
|
sectionPayload elfSection64
|
||||||
Len: int(sectionData[ptrElfSections.strtabSectionIndex].size),
|
ptrElfSections = (*elfSections)(unsafe.Pointer(curPtr))
|
||||||
Cap: int(sectionData[ptrElfSections.strtabSectionIndex].size),
|
secPtr = uintptr(unsafe.Pointer(&ptrElfSections.sectionData))
|
||||||
Data: uintptr(sectionData[ptrElfSections.strtabSectionIndex].address),
|
sizeofSection = unsafe.Sizeof(sectionPayload)
|
||||||
}))
|
strTableSection = (*elfSection64)(unsafe.Pointer(secPtr + uintptr(ptrElfSections.strtabSectionIndex)*sizeofSection))
|
||||||
|
secName string
|
||||||
|
secNameHeader = (*reflect.StringHeader)(unsafe.Pointer(&secName))
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, secData := range sectionData {
|
for secIndex := uint16(0); secIndex < ptrElfSections.numSections; secIndex, secPtr = secIndex+1, secPtr+sizeofSection {
|
||||||
|
secData := (*elfSection64)(unsafe.Pointer(secPtr))
|
||||||
if secData.size == 0 {
|
if secData.size == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// String table entries are C-style NULL-terminated strings
|
// String table entries are C-style NULL-terminated strings
|
||||||
end := secData.nameIndex
|
end := uintptr(secData.nameIndex)
|
||||||
for ; strTable[end] != 0; end++ {
|
for ; *(*byte)(unsafe.Pointer(uintptr(strTableSection.address) + end)) != 0; end++ {
|
||||||
}
|
}
|
||||||
|
|
||||||
elfSectionList = append(elfSectionList, &ElfSection{
|
secNameHeader.Len = int(end - uintptr(secData.nameIndex))
|
||||||
Name: string(strTable[secData.nameIndex:end]),
|
secNameHeader.Data = uintptr(unsafe.Pointer(uintptr(strTableSection.address) + uintptr(secData.nameIndex)))
|
||||||
Flags: ElfSectionFlag(secData.flags),
|
|
||||||
Address: uintptr(secData.address),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return elfSectionList
|
visitor(secName, ElfSectionFlag(secData.flags), uintptr(secData.address), secData.size)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetInfoPtr updates the internal multiboot information pointer to the given
|
// SetInfoPtr updates the internal multiboot information pointer to the given
|
||||||
|
@ -196,9 +196,9 @@ func TestGetBootCmdLine(t *testing.T) {
|
|||||||
func TestGetElfSections(t *testing.T) {
|
func TestGetElfSections(t *testing.T) {
|
||||||
SetInfoPtr(uintptr(unsafe.Pointer(&emptyInfoData[0])))
|
SetInfoPtr(uintptr(unsafe.Pointer(&emptyInfoData[0])))
|
||||||
|
|
||||||
if GetElfSections() != nil {
|
VisitElfSections(func(_ string, _ ElfSectionFlag, _ uintptr, _ uint64) {
|
||||||
t.Fatalf("expected GetElfSections() to return nil when no elf sections tag is present")
|
t.Fatalf("expected GetElfSections() to return nil when no elf sections tag is present")
|
||||||
}
|
})
|
||||||
|
|
||||||
SetInfoPtr(uintptr(unsafe.Pointer(&multibootInfoTestData[0])))
|
SetInfoPtr(uintptr(unsafe.Pointer(&multibootInfoTestData[0])))
|
||||||
|
|
||||||
@ -209,43 +209,45 @@ func TestGetElfSections(t *testing.T) {
|
|||||||
multibootInfoTestData[1660+i] = b
|
multibootInfoTestData[1660+i] = b
|
||||||
}
|
}
|
||||||
|
|
||||||
sections := GetElfSections()
|
// There are more sections in the test data but we will only focus on these ones for the test
|
||||||
|
var (
|
||||||
|
expSections = []struct {
|
||||||
|
secName string
|
||||||
|
expFlags ElfSectionFlag
|
||||||
|
}{
|
||||||
|
{".text", ElfSectionAllocated | ElfSectionExecutable},
|
||||||
|
{".bss", ElfSectionAllocated | ElfSectionWritable},
|
||||||
|
{".noptrbss", ElfSectionAllocated | ElfSectionWritable},
|
||||||
|
{".data", ElfSectionAllocated | ElfSectionWritable},
|
||||||
|
{".rodata", ElfSectionAllocated},
|
||||||
|
{".strtab", 0},
|
||||||
|
}
|
||||||
|
matchedSections int
|
||||||
|
)
|
||||||
|
|
||||||
specs := []struct {
|
VisitElfSections(func(secName string, secFlags ElfSectionFlag, _ uintptr, secSize uint64) {
|
||||||
secName string
|
for secIndex, sec := range expSections {
|
||||||
expFlags ElfSectionFlag
|
if secName != sec.secName {
|
||||||
}{
|
continue
|
||||||
{".text", ElfSectionAllocated | ElfSectionExecutable},
|
|
||||||
{".bss", ElfSectionAllocated | ElfSectionWritable},
|
|
||||||
{".noptrbss", ElfSectionAllocated | ElfSectionWritable},
|
|
||||||
{".data", ElfSectionAllocated | ElfSectionWritable},
|
|
||||||
{".rodata", ElfSectionAllocated},
|
|
||||||
{".strtab", 0},
|
|
||||||
}
|
|
||||||
|
|
||||||
for specIndex, spec := range specs {
|
|
||||||
var found *ElfSection
|
|
||||||
for _, sec := range sections {
|
|
||||||
if sec.Name == spec.secName {
|
|
||||||
found = sec
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if found == nil {
|
if secFlags != sec.expFlags {
|
||||||
t.Errorf("[spec %d] missing section %q", specIndex, spec.secName)
|
t.Errorf("[section %d] expected section flags to be: 0x%x; got 0x%x", secIndex, sec.expFlags, secFlags)
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if found.Flags != spec.expFlags {
|
if secSize == 0 {
|
||||||
t.Errorf("[spec %d] expected section flags to be: 0x%x; got 0x%x", specIndex, spec.expFlags, found.Flags)
|
t.Errorf("[section %d] expected section size to be > 0", secIndex)
|
||||||
}
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second call should return the memoized data
|
matchedSections++
|
||||||
sections[0].Name = "foo"
|
return
|
||||||
if sections2 := GetElfSections(); !reflect.DeepEqual(sections2, sections) {
|
}
|
||||||
t.Error("expected second call to GetElfSections() to return the memoized section list")
|
})
|
||||||
|
|
||||||
|
if exp := len(expSections); matchedSections != exp {
|
||||||
|
t.Fatalf("expected to match %d sections; matched %d", exp, matchedSections)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user