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"
 | 
						"unsafe"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						infoData       uintptr
 | 
				
			||||||
 | 
						cmdLineKV      map[string]string
 | 
				
			||||||
 | 
						elfSectionList []*ElfSection
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type tagType uint32
 | 
					type tagType uint32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// nolint
 | 
					// nolint
 | 
				
			||||||
@ -140,11 +146,6 @@ const (
 | 
				
			|||||||
	memUnknown
 | 
						memUnknown
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					 | 
				
			||||||
	infoData  uintptr
 | 
					 | 
				
			||||||
	cmdLineKV map[string]string
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 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.
 | 
				
			||||||
@ -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
 | 
					// SetInfoPtr updates the internal multiboot information pointer to the given
 | 
				
			||||||
// value. This function must be invoked before invoking any other function
 | 
					// value. This function must be invoked before invoking any other function
 | 
				
			||||||
// exported by this package.
 | 
					// exported by this package.
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,8 @@
 | 
				
			|||||||
package multiboot
 | 
					package multiboot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"encoding/binary"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"unsafe"
 | 
						"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 (
 | 
					var (
 | 
				
			||||||
	emptyInfoData = []byte{
 | 
						emptyInfoData = []byte{
 | 
				
			||||||
		0, 0, 0, 0, // size
 | 
							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,
 | 
							0x59, 0x42, 0x4f, 0x43, 0x48, 0x53, 0x20, 0x00, 0xdc, 0x18, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x00,
 | 
				
			||||||
		0x00, 0x00, 0x00, 0x00, 0x08, 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