mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
Support parsing of 64-bit ELF section tags off from the multiboot data
This commit is contained in:
parent
af9613e336
commit
a79be7c268
@ -6,6 +6,12 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
infoData uintptr
|
||||
cmdLineKV map[string]string
|
||||
elfSectionList []*ElfSection
|
||||
)
|
||||
|
||||
type tagType uint32
|
||||
|
||||
// nolint
|
||||
@ -140,11 +146,6 @@ const (
|
||||
memUnknown
|
||||
)
|
||||
|
||||
var (
|
||||
infoData uintptr
|
||||
cmdLineKV map[string]string
|
||||
)
|
||||
|
||||
// MemRegionVisitor defies a visitor function that gets invoked by VisitMemRegions
|
||||
// for each memory region provided by the boot loader. The visitor must return true
|
||||
// to continue or false to abort the scan.
|
||||
@ -179,6 +180,115 @@ func (t MemoryEntryType) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
type elfSections struct {
|
||||
numSections uint16
|
||||
sectionSize uint32
|
||||
strtabSectionIndex uint32
|
||||
sectionData [0]byte
|
||||
}
|
||||
|
||||
/*
|
||||
type elfSection32 struct {
|
||||
nameIndex uint32
|
||||
sectionType uint32
|
||||
flags uint32
|
||||
address uint32
|
||||
offset uint32
|
||||
size uint32
|
||||
link uint32
|
||||
info uint32
|
||||
addrAlign uint32
|
||||
entSize uint32
|
||||
}
|
||||
*/
|
||||
|
||||
type elfSection64 struct {
|
||||
nameIndex uint32
|
||||
sectionType uint32
|
||||
flags uint64
|
||||
address uint64
|
||||
offset uint64
|
||||
size uint64
|
||||
link uint32
|
||||
info uint32
|
||||
addrAlign uint64
|
||||
entSize uint64
|
||||
}
|
||||
|
||||
// ElfSectionFlag defines an OR-able flag associated with an ElfSection.
|
||||
type ElfSectionFlag uint32
|
||||
|
||||
const (
|
||||
// ElfSectionWritable marks the section as writable.
|
||||
ElfSectionWritable ElfSectionFlag = 1 << iota
|
||||
|
||||
// ElfSectionAllocated means that the section is allocated in memory
|
||||
// when the image is loaded (e.g .bss sections)
|
||||
ElfSectionAllocated
|
||||
|
||||
// ElfSectionExecutable marks the section as executable.
|
||||
ElfSectionExecutable
|
||||
)
|
||||
|
||||
// ElfSection deefines the name, flags and virtual address of an ELF section
|
||||
// which is part of the kernel image.
|
||||
type ElfSection struct {
|
||||
// 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
|
||||
}
|
||||
|
||||
curPtr, size := findTagByType(tagElfSymbols)
|
||||
if size == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
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 (
|
||||
strTable = *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
|
||||
Len: int(sectionData[ptrElfSections.strtabSectionIndex].size),
|
||||
Cap: int(sectionData[ptrElfSections.strtabSectionIndex].size),
|
||||
Data: uintptr(sectionData[ptrElfSections.strtabSectionIndex].address),
|
||||
}))
|
||||
)
|
||||
|
||||
for _, secData := range sectionData {
|
||||
if secData.size == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// String table entries are C-style NULL-terminated strings
|
||||
end := secData.nameIndex
|
||||
for ; strTable[end] != 0; end++ {
|
||||
}
|
||||
|
||||
elfSectionList = append(elfSectionList, &ElfSection{
|
||||
Name: string(strTable[secData.nameIndex:end]),
|
||||
Flags: ElfSectionFlag(secData.flags),
|
||||
Address: uintptr(secData.address),
|
||||
})
|
||||
}
|
||||
|
||||
return elfSectionList
|
||||
}
|
||||
|
||||
// SetInfoPtr updates the internal multiboot information pointer to the given
|
||||
// value. This function must be invoked before invoking any other function
|
||||
// exported by this package.
|
||||
|
@ -1,6 +1,8 @@
|
||||
package multiboot
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"reflect"
|
||||
"testing"
|
||||
"unsafe"
|
||||
@ -191,6 +193,62 @@ func TestGetBootCmdLine(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetElfSections(t *testing.T) {
|
||||
SetInfoPtr(uintptr(unsafe.Pointer(&emptyInfoData[0])))
|
||||
|
||||
if GetElfSections() != nil {
|
||||
t.Fatalf("expected GetElfSections() to return nil when no elf sections tag is present")
|
||||
}
|
||||
|
||||
SetInfoPtr(uintptr(unsafe.Pointer(&multibootInfoTestData[0])))
|
||||
|
||||
// Patch the strtab address to point to out mock data
|
||||
var buf bytes.Buffer
|
||||
binary.Write(&buf, binary.LittleEndian, uint64(uintptr(unsafe.Pointer(&mockStrTable[0]))))
|
||||
for i, b := range buf.Bytes() {
|
||||
multibootInfoTestData[1660+i] = b
|
||||
}
|
||||
|
||||
sections := GetElfSections()
|
||||
|
||||
specs := []struct {
|
||||
secName string
|
||||
expFlags ElfSectionFlag
|
||||
}{
|
||||
{".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 {
|
||||
t.Errorf("[spec %d] missing section %q", specIndex, spec.secName)
|
||||
continue
|
||||
}
|
||||
|
||||
if found.Flags != spec.expFlags {
|
||||
t.Errorf("[spec %d] expected section flags to be: 0x%x; got 0x%x", specIndex, spec.expFlags, found.Flags)
|
||||
}
|
||||
}
|
||||
|
||||
// Second call should return the memoized data
|
||||
sections[0].Name = "foo"
|
||||
if sections2 := GetElfSections(); !reflect.DeepEqual(sections2, sections) {
|
||||
t.Error("expected second call to GetElfSections() to return the memoized section list")
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
emptyInfoData = []byte{
|
||||
0, 0, 0, 0, // size
|
||||
@ -374,4 +432,23 @@ var (
|
||||
0x59, 0x42, 0x4f, 0x43, 0x48, 0x53, 0x20, 0x00, 0xdc, 0x18, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
}
|
||||
|
||||
mockStrTable = []byte{
|
||||
0x00, 0x2e, 0x73, 0x79, 0x6d, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x73, 0x74, 0x72, 0x74, 0x61, 0x62, // ..symtab..strtab
|
||||
0x00, 0x2e, 0x73, 0x68, 0x73, 0x74, 0x72, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x74, 0x65, 0x78, 0x74, // ..shstrtab..text
|
||||
0x00, 0x2e, 0x72, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x00, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x6c, 0x69, // ..rodata..typeli
|
||||
0x6e, 0x6b, 0x00, 0x2e, 0x69, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x6e, 0x6b, 0x00, 0x2e, 0x67, 0x6f, // nk..itablink..go
|
||||
0x70, 0x63, 0x6c, 0x6e, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x00, 0x2e, 0x6e, // pclntab..data..n
|
||||
0x6f, 0x70, 0x74, 0x72, 0x64, 0x61, 0x74, 0x61, 0x00, 0x2e, 0x62, 0x73, 0x73, 0x00, 0x2e, 0x6e, // optrdata..bss..n
|
||||
0x6f, 0x70, 0x74, 0x72, 0x62, 0x73, 0x73, 0x00, 0x2e, 0x67, 0x6f, 0x72, 0x65, 0x64, 0x69, 0x72, // optrbss..goredir
|
||||
0x65, 0x63, 0x74, 0x73, 0x74, 0x62, 0x6c, 0x00, 0x2e, 0x6e, 0x6f, 0x74, 0x65, 0x2e, 0x67, 0x6f, // ectstbl..note.go
|
||||
0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x69, 0x64, 0x00, 0x2e, 0x74, 0x62, 0x73, 0x73, 0x00, 0x2e, // .buildid..tbss..
|
||||
0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x61, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x00, 0x2e, 0x64, // debug_aranges..d
|
||||
0x65, 0x62, 0x75, 0x67, 0x5f, 0x70, 0x75, 0x62, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x00, 0x2e, 0x64, // ebug_pubnames..d
|
||||
0x65, 0x62, 0x75, 0x67, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, // ebug_info..debug
|
||||
0x5f, 0x61, 0x62, 0x62, 0x72, 0x65, 0x76, 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x6c, // _abbrev..debug_l
|
||||
0x69, 0x6e, 0x65, 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, // ine..debug_frame
|
||||
0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x6c, 0x6f, 0x63, 0x00, 0x2e, 0x64, 0x65, 0x62, // ..debug_loc..deb
|
||||
0x75, 0x67, 0x5f, 0x70, 0x75, 0x62, 0x74, 0x79, 0x70, 0x65, 0x73, 0x00, // ug_pubtypes.
|
||||
}
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user