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 ( | ||||
| 	infoData       uintptr | ||||
| 	cmdLineKV      map[string]string | ||||
| 	elfSectionList []*ElfSection | ||||
| 	infoData  uintptr | ||||
| 	cmdLineKV map[string]string | ||||
| ) | ||||
| 
 | ||||
| type tagType uint32 | ||||
| @ -149,7 +148,7 @@ const ( | ||||
| // 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. | ||||
| type MemRegionVisitor func(entry *MemoryMapEntry) bool | ||||
| type MemRegionVisitor func(*MemoryMapEntry) bool | ||||
| 
 | ||||
| // MemoryMapEntry describes a memory region entry, namely its physical address, | ||||
| // its length and its type. | ||||
| @ -230,63 +229,44 @@ const ( | ||||
| 	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 | ||||
| 	} | ||||
| // ElfSectionVisitor defies a visitor function that gets invoked by VisitElfSections | ||||
| // for rach ELF section that belongs to the loaded kernel image. | ||||
| type ElfSectionVisitor func(name string, flags ElfSectionFlag, address uintptr, size uint64) | ||||
| 
 | ||||
| // VisitElfSections invokes visitor for each ELF entry that belongs to the | ||||
| // loaded kernel image. | ||||
| func VisitElfSections(visitor ElfSectionVisitor) { | ||||
| 	curPtr, size := findTagByType(tagElfSymbols) | ||||
| 	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 ( | ||||
| 		strTable = *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ | ||||
| 			Len:  int(sectionData[ptrElfSections.strtabSectionIndex].size), | ||||
| 			Cap:  int(sectionData[ptrElfSections.strtabSectionIndex].size), | ||||
| 			Data: uintptr(sectionData[ptrElfSections.strtabSectionIndex].address), | ||||
| 		})) | ||||
| 		sectionPayload  elfSection64 | ||||
| 		ptrElfSections  = (*elfSections)(unsafe.Pointer(curPtr)) | ||||
| 		secPtr          = uintptr(unsafe.Pointer(&ptrElfSections.sectionData)) | ||||
| 		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 { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		// String table entries are C-style NULL-terminated strings | ||||
| 		end := secData.nameIndex | ||||
| 		for ; strTable[end] != 0; end++ { | ||||
| 		end := uintptr(secData.nameIndex) | ||||
| 		for ; *(*byte)(unsafe.Pointer(uintptr(strTableSection.address) + end)) != 0; end++ { | ||||
| 		} | ||||
| 
 | ||||
| 		elfSectionList = append(elfSectionList, &ElfSection{ | ||||
| 			Name:    string(strTable[secData.nameIndex:end]), | ||||
| 			Flags:   ElfSectionFlag(secData.flags), | ||||
| 			Address: uintptr(secData.address), | ||||
| 		}) | ||||
| 	} | ||||
| 		secNameHeader.Len = int(end - uintptr(secData.nameIndex)) | ||||
| 		secNameHeader.Data = uintptr(unsafe.Pointer(uintptr(strTableSection.address) + uintptr(secData.nameIndex))) | ||||
| 
 | ||||
| 	return elfSectionList | ||||
| 		visitor(secName, ElfSectionFlag(secData.flags), uintptr(secData.address), secData.size) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // SetInfoPtr updates the internal multiboot information pointer to the given | ||||
|  | ||||
| @ -196,9 +196,9 @@ func TestGetBootCmdLine(t *testing.T) { | ||||
| func TestGetElfSections(t *testing.T) { | ||||
| 	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") | ||||
| 	} | ||||
| 	}) | ||||
| 
 | ||||
| 	SetInfoPtr(uintptr(unsafe.Pointer(&multibootInfoTestData[0]))) | ||||
| 
 | ||||
| @ -209,43 +209,45 @@ func TestGetElfSections(t *testing.T) { | ||||
| 		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 { | ||||
| 		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 | ||||
| 	VisitElfSections(func(secName string, secFlags ElfSectionFlag, _ uintptr, secSize uint64) { | ||||
| 		for secIndex, sec := range expSections { | ||||
| 			if secName != sec.secName { | ||||
| 				continue | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if found == nil { | ||||
| 			t.Errorf("[spec %d] missing section %q", specIndex, spec.secName) | ||||
| 			continue | ||||
| 		} | ||||
| 			if secFlags != sec.expFlags { | ||||
| 				t.Errorf("[section %d] expected section flags to be: 0x%x; got 0x%x", secIndex, sec.expFlags, secFlags) | ||||
| 				return | ||||
| 			} | ||||
| 
 | ||||
| 		if found.Flags != spec.expFlags { | ||||
| 			t.Errorf("[spec %d] expected section flags to be: 0x%x; got 0x%x", specIndex, spec.expFlags, found.Flags) | ||||
| 		} | ||||
| 	} | ||||
| 			if secSize == 0 { | ||||
| 				t.Errorf("[section %d] expected section size to be > 0", secIndex) | ||||
| 				return | ||||
| 			} | ||||
| 
 | ||||
| 	// 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") | ||||
| 			matchedSections++ | ||||
| 			return | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	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