From 75162aa1199939c4b3a3fba69306f6e50cab0b6a Mon Sep 17 00:00:00 2001 From: Gaulthier Gain Date: Fri, 10 Dec 2021 20:00:22 +0100 Subject: [PATCH] Update --- lds/common.ld | 86 ++++++++ srcs/binarytool/elf64analyser/elf_analyser.go | 61 +++--- srcs/binarytool/elf64analyser/elf_pages.go | 8 +- srcs/binarytool/run_binarytool.go | 11 +- srcs/binarytool/ukManager/elf_linker.go | 103 ++++++++++ srcs/binarytool/ukManager/helpers.go | 18 -- srcs/binarytool/ukManager/manager.go | 185 +++++++++++++----- srcs/binarytool/ukManager/unikernels.go | 126 ++++++++++-- 8 files changed, 468 insertions(+), 130 deletions(-) create mode 100644 lds/common.ld create mode 100644 srcs/binarytool/ukManager/elf_linker.go diff --git a/lds/common.ld b/lds/common.ld new file mode 100644 index 0000000..b0e8cca --- /dev/null +++ b/lds/common.ld @@ -0,0 +1,86 @@ +SECTIONS +{ + . = 0x100000; + _text = .; + .text : + { + KEEP (*(.data.boot)) + *(.text.boot) + *(.text) + *(.text.*) /* uncomment it to dissagregate functions */ + } + + + _etext = .; + . = ALIGN((1 << 12)); __eh_frame_start = .; .eh_frame : { *(.eh_frame) *(.eh_frame.*) } __eh_frame_end = .; __eh_frame_hdr_start = .; .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_hdr.*) } __eh_frame_hdr_end = .; + . = ALIGN((1 << 12)); uk_ctortab_start = .; .uk_ctortab : { KEEP(*(SORT_BY_NAME(.uk_ctortab[0-9]))) } uk_ctortab_end = .; + uk_inittab_start = .; .uk_inittab : { KEEP(*(SORT_BY_NAME(.uk_inittab[1-6][0-9]))) } uk_inittab_end = .; + + + . = ALIGN((1 << 12)); + _rodata = .; + .rodata : + { + + *(.rodata) + *(.rodata.*) + } + + + _erodata = .; + . = ALIGN(0x8); + _ctors = .; + .preinit_array : { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + . = ALIGN(0x8); + .init_array : { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + _ectors = .; + . = ALIGN(0x8); _tls_start = .; .tdata : { *(.tdata) *(.tdata.*) *(.gnu.linkonce.td.*) } _etdata = .; + + + . = ALIGN((1 << 12)); + _data = .; + .data : + { + + *(.data) + *(.data.*) + } + + + _edata = .; + . = ALIGN((1 << 12)); + + + __bss_start = .; + .bss : + { + + *(.bss) + *(.bss.*) + *(COMMON) + . = ALIGN((1 << 12)); + } + + + .tbss : { *(.tbss) *(.tbss.*) *(.gnu.linkonce.tb.*) . = ALIGN(0x8); } _tls_end = . + SIZEOF(.tbss); + + + .intrstack : + { + *(.intrstack) + . = ALIGN((1 << 12)); + } + _end = .; + .comment 0 : { *(.comment) } + .debug 0 : { *(.debug) } .line 0 : { *(.line) } .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } .debug_weaknames 0 : { *(.debug_weaknames) } .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } .debug_pubtypes 0 : { *(.debug_pubtypes) } .debug_ranges 0 : { *(.debug_ranges) } .debug_macro 0 : { *(.debug_macro) } .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + /DISCARD/ : { *(.note.gnu.build-id) } +} \ No newline at end of file diff --git a/srcs/binarytool/elf64analyser/elf_analyser.go b/srcs/binarytool/elf64analyser/elf_analyser.go index 78ad0ad..98edd48 100644 --- a/srcs/binarytool/elf64analyser/elf_analyser.go +++ b/srcs/binarytool/elf64analyser/elf_analyser.go @@ -7,8 +7,6 @@ package elf64analyser import ( - "crypto/sha256" - "encoding/hex" "fmt" "os" "sort" @@ -19,8 +17,9 @@ import ( ) type ElfAnalyser struct { - ElfLibs []ElfLibs - ElfPage []*ElfPage + ElfLibs []ElfLibs + ElfPage []*ElfPage + MapElfLibs map[string]*ElfLibs } type ElfLibs struct { @@ -29,6 +28,10 @@ type ElfLibs struct { EndAddr uint64 Size uint64 NbSymbols int + + RodataSize uint64 + DataSize uint64 + BssSize uint64 } func (analyser *ElfAnalyser) DisplayMapping() { @@ -151,30 +154,11 @@ func compareFunctions(elf *elf64core.ELF64File, obj *elf64core.ELF64File) (uint6 elfFuncsAll[len(elfFuncsAll)-1].Addr, len(elfFuncsAll) } -func (analyser *ElfAnalyser) InspectMapping(elf *elf64core.ELF64File, objs ...interface{}) { - - if len(objs) == 0 { - return +func getSectionSize(name string, obj *elf64core.ELF64File) uint64 { + if index, ok := obj.IndexSections[name]; ok { + return obj.SectionsTable.DataSect[index].Elf64section.Size } - - analyser.ElfLibs = make([]ElfLibs, 0) - for _, iobj := range objs { - obj := iobj.(*elf64core.ELF64File) - start, end, nbSymbols := compareFunctions(elf, obj) - analyser.ElfLibs = append(analyser.ElfLibs, ElfLibs{ - Name: obj.Name, - StartAddr: start, - EndAddr: end, - Size: end - start, - NbSymbols: nbSymbols, - }) - return - } - - // sort functions - sort.Slice(analyser.ElfLibs, func(i, j int) bool { - return analyser.ElfLibs[i].StartAddr < analyser.ElfLibs[j].StartAddr - }) + return 0 } func (analyser *ElfAnalyser) InspectMappingList(elf *elf64core.ELF64File, @@ -184,16 +168,25 @@ func (analyser *ElfAnalyser) InspectMappingList(elf *elf64core.ELF64File, return } - analyser.ElfLibs = make([]ElfLibs, 0) - for _, obj := range objs { + analyser.ElfLibs = make([]ElfLibs, len(objs)) + analyser.MapElfLibs = make(map[string]*ElfLibs, len(analyser.ElfLibs)) + for i, obj := range objs { + start, end, nbSymbols := compareFunctions(elf, obj) - analyser.ElfLibs = append(analyser.ElfLibs, ElfLibs{ + lib := ElfLibs{ Name: obj.Name, StartAddr: start, EndAddr: end, Size: end - start, NbSymbols: nbSymbols, - }) + // Get size of data, rodata and bss from object file + RodataSize: getSectionSize(".rodata", obj), + DataSize: getSectionSize(".data", obj), + BssSize: getSectionSize(".bss", obj), + } + analyser.ElfLibs[i] = lib + // Map for direct access + analyser.MapElfLibs[lib.Name] = &lib } // sort functions by start address. @@ -202,6 +195,7 @@ func (analyser *ElfAnalyser) InspectMappingList(elf *elf64core.ELF64File, }) } +/* func (analyser *ElfAnalyser) SplitIntoPagesBySection(elfFile *elf64core.ELF64File, sectionName string) { if len(analyser.ElfPage) == 0 { @@ -211,8 +205,7 @@ func (analyser *ElfAnalyser) SplitIntoPagesBySection(elfFile *elf64core.ELF64Fil if strings.Contains(sectionName, elf64core.TextSection) { // An ELF might have several text sections for _, indexSection := range elfFile.TextSectionIndex { - sectionName := elfFile.SectionsTable.DataSect[indexSection].Name - analyser.computePage(elfFile, sectionName, indexSection) + analyser.computePage(elfFile, elfFile.SectionsTable.DataSect[indexSection].Name, indexSection) } } else if indexSection, ok := elfFile.IndexSections[sectionName]; ok { analyser.computePage(elfFile, sectionName, indexSection) @@ -221,6 +214,7 @@ func (analyser *ElfAnalyser) SplitIntoPagesBySection(elfFile *elf64core.ELF64Fil } } + func CreateNewPage(startAddress uint64, k int, raw []byte) *ElfPage { byteArray := make([]byte, PageSize) b := raw @@ -253,3 +247,4 @@ func (analyser *ElfAnalyser) computePage(elfFile *elf64core.ELF64File, section s k++ } } +*/ diff --git a/srcs/binarytool/elf64analyser/elf_pages.go b/srcs/binarytool/elf64analyser/elf_pages.go index 5bd0951..1a01356 100644 --- a/srcs/binarytool/elf64analyser/elf_pages.go +++ b/srcs/binarytool/elf64analyser/elf_pages.go @@ -53,13 +53,7 @@ func (p *ElfPage) pageContentToString() string { } func (p *ElfPage) displayPageContent(mw io.Writer) { - - /* - hexStartAddr, err := strconv.ParseInt(p.startAddress, 16, 64); - if err != nil { - panic(err) - } - */ + for i, entry := range p.contentByteArray { if i > 0 && i%4 == 0 { diff --git a/srcs/binarytool/run_binarytool.go b/srcs/binarytool/run_binarytool.go index 4b758fd..23cd761 100644 --- a/srcs/binarytool/run_binarytool.go +++ b/srcs/binarytool/run_binarytool.go @@ -37,14 +37,14 @@ func RunBinaryAnalyser(homeDir string) { manager := new(ukManager.Manager) manager.MicroLibs = make(map[string]*ukManager.MicroLib) if len(*args.StringArg[listArg]) > 0 { - manager.Unikernels = make([]ukManager.Unikernel, len(*args.StringArg[listArg])) + manager.Unikernels = make([]*ukManager.Unikernel, len(*args.StringArg[listArg])) mapping := false if *args.BoolArg[mappingArg] { mapping = true } list := strings.Split(*args.StringArg[listArg], ",") for i, arg := range list { - manager.Unikernels[i] = ukManager.Unikernel{ + manager.Unikernels[i] = &ukManager.Unikernel{ BuildPath: arg, DisplayMapping: mapping, } @@ -62,10 +62,9 @@ func RunBinaryAnalyser(homeDir string) { var comparison elf64analyser.ComparisonElf comparison.GroupFileSegment = make([]*elf64analyser.ElfFileSegment, 0) - for i, _ := range manager.Unikernels { + for i, uk := range manager.Unikernels { - manager.Unikernels[i].Analyser = new(elf64analyser.ElfAnalyser) - uk := manager.Unikernels[i] + uk.Analyser = new(elf64analyser.ElfAnalyser) if len(uk.BuildPath) > 0 { if uk.BuildPath[len(uk.BuildPath)-1] != os.PathSeparator { uk.BuildPath += u.SEP @@ -104,7 +103,7 @@ func RunBinaryAnalyser(homeDir string) { uk.Analyser.FindSectionByAddress(uk.ElfFile, uk.FindSectionByAddress) } - manager.ComputeAlignment(uk) + manager.ComputeAlignment(*uk) /*if uk.CompareGroup > 0 { diff --git a/srcs/binarytool/ukManager/elf_linker.go b/srcs/binarytool/ukManager/elf_linker.go new file mode 100644 index 0000000..373c7de --- /dev/null +++ b/srcs/binarytool/ukManager/elf_linker.go @@ -0,0 +1,103 @@ +package ukManager + +import ( + "bufio" + "fmt" + "log" + "os" + "strings" + "tools/srcs/binarytool/elf64analyser" + "tools/srcs/binarytool/elf64core" +) + +type LinkerInfo struct { + ldsString string + rodataAddr uint64 + dataAddr uint64 + bssAddr uint64 +} + +const ( + endtext_location = "" + rodata_location = "" + data_location = "" + erodata_location = "" + edata_location = "" + bss_location = "" + tbss_location = "" + intrstack_location = "" + ukinit_location = "" + + inner_rodata = "" + inner_data = "" + inner_bss = "" +) + +func readLdsContent(filename string) string { + + strBuilder := strings.Builder{} + file, err := os.Open(filename) + if err != nil { + log.Fatal(err) + } + defer file.Close() + + scanner := bufio.NewScanner(file) + // optionally, resize scanner's capacity for lines over 64K, see next example + for scanner.Scan() { + strBuilder.WriteString(scanner.Text() + "\n") + } + + if err := scanner.Err(); err != nil { + log.Fatal(err) + } + return strBuilder.String() +} + +func processLdsFile(locationCnt uint64, maxValSection map[string]uint64) LinkerInfo { + + type sectionLoc struct { + sec string + loc string + } + + linkerInfo := LinkerInfo{} + + // Use an array to preserver order + arrSection := []sectionLoc{ + {sec: elf64core.RodataSection, loc: rodata_location}, + {sec: elf64core.DataSection, loc: data_location}, + {sec: elf64core.BssSection, loc: bss_location}, + {sec: elf64core.TbssSection, loc: tbss_location}} + + ldsString := readLdsContent("lds/common.ld") + // Update end of text + ldsString = strings.Replace(ldsString, endtext_location, fmt.Sprintf(". = 0x%x;", locationCnt), -1) + // Update ukinit + ldsString = strings.Replace(ldsString, ukinit_location, fmt.Sprintf(". = 0x%x;", locationCnt+0x40), -1) + + locationCnt += elf64analyser.PageSize + for _, sect := range arrSection { + if sect.sec == elf64core.RodataSection { + linkerInfo.rodataAddr = locationCnt + } else if sect.sec == elf64core.DataSection { + // Update erodata just before data + ldsString = strings.Replace(ldsString, erodata_location, fmt.Sprintf(". = 0x%x;", locationCnt), -1) + locationCnt += elf64analyser.PageSize + linkerInfo.dataAddr = locationCnt + } else if sect.sec == elf64core.BssSection { + // Update edata just before bss + ldsString = strings.Replace(ldsString, edata_location, fmt.Sprintf(". = 0x%x;", locationCnt), -1) + locationCnt += elf64analyser.PageSize + linkerInfo.bssAddr = locationCnt + } + // Update rodata, data, bss, tbss + ldsString = strings.Replace(ldsString, sect.loc, fmt.Sprintf(". = 0x%x;", locationCnt), -1) + locationCnt += maxValSection[sect.sec] + locationCnt = roundAddr(locationCnt, elf64analyser.PageSize) + } + // Update intrstack + linkerInfo.ldsString = strings.Replace(ldsString, intrstack_location, fmt.Sprintf(". = 0x%x;", locationCnt), -1) + + return linkerInfo +} diff --git a/srcs/binarytool/ukManager/helpers.go b/srcs/binarytool/ukManager/helpers.go index a507878..cd6b9d5 100644 --- a/srcs/binarytool/ukManager/helpers.go +++ b/srcs/binarytool/ukManager/helpers.go @@ -7,27 +7,9 @@ package ukManager import ( - "encoding/json" - "io/ioutil" - "os" "strings" ) -func ReadJsonFile(path string) ([]Unikernel, error) { - jsonFile, err := os.Open(path) - if err != nil { - return nil, err - } - defer jsonFile.Close() - byteValue, _ := ioutil.ReadAll(jsonFile) - unikernels := new(Unikernels) - if err := json.Unmarshal(byteValue, unikernels); err != nil { - return nil, err - } - - return unikernels.Unikernel, nil -} - func stringInSlice(name string, plats []string) bool { for _, plat := range plats { if strings.Contains(name, plat) { diff --git a/srcs/binarytool/ukManager/manager.go b/srcs/binarytool/ukManager/manager.go index c370ed1..803e3bd 100644 --- a/srcs/binarytool/ukManager/manager.go +++ b/srcs/binarytool/ukManager/manager.go @@ -4,12 +4,16 @@ import ( "fmt" "math" "sort" + "strings" "tools/srcs/binarytool/elf64analyser" + "tools/srcs/binarytool/elf64core" u "tools/srcs/common" ) +const ukbootMain = "libukboot_main.ld.o" + type Manager struct { - Unikernels []Unikernel + Unikernels []*Unikernel MicroLibs map[string]*MicroLib SortedMicroLibs []*MicroLib //Used for the display } @@ -19,24 +23,38 @@ type MicroLib struct { startAddr uint64 size uint64 instance int - sectionSize SectionMicroLibs + sectionSize *SectionMicroLibs } type SectionMicroLibs struct { rodataSize uint64 dataSize uint64 - BssSize uint64 + bssSize uint64 + + rodataAddr uint64 + dataAddr uint64 + bssAddr uint64 } func (manager *Manager) ComputeAlignment(unikernel Unikernel) { for _, libs := range unikernel.Analyser.ElfLibs { + + // Ignore ukbootMain to place it to specific position + if libs.Name == ukbootMain { + continue + } + + // Add microlib to a global map per instance if val, ok := manager.MicroLibs[libs.Name]; ok { if manager.MicroLibs[libs.Name].size != libs.Size { //u.PrintWarning(fmt.Sprintf("Different size between %s (0x%x) (0x%x)", libs.Name, libs.Size, val.size)) if val.size < libs.Size { u.PrintWarning(fmt.Sprintf("Bigger size found %s (0x%x) > (0x%x)", libs.Name, libs.Size, val.size)) manager.MicroLibs[libs.Name].size = libs.Size + manager.MicroLibs[libs.Name].sectionSize.rodataSize = libs.RodataSize + manager.MicroLibs[libs.Name].sectionSize.dataSize = libs.DataSize + manager.MicroLibs[libs.Name].sectionSize.bssSize = libs.BssSize } } manager.MicroLibs[libs.Name].instance += 1 @@ -46,6 +64,11 @@ func (manager *Manager) ComputeAlignment(unikernel Unikernel) { startAddr: libs.StartAddr, size: libs.Size, instance: 1, + sectionSize: &SectionMicroLibs{ + rodataSize: libs.RodataSize, + dataSize: libs.DataSize, + bssSize: libs.BssSize, + }, } manager.MicroLibs[libs.Name] = mlib } @@ -58,7 +81,6 @@ func (manager *Manager) sortMicroLibs() { instance int addr uint64 } - i := 0 var kvSlice = make([]kv, len(manager.MicroLibs)) for k, v := range manager.MicroLibs { @@ -74,71 +96,142 @@ func (manager *Manager) sortMicroLibs() { }) manager.SortedMicroLibs = make([]*MicroLib, len(manager.MicroLibs)) - for i, lib := range kvSlice { - manager.SortedMicroLibs[i] = manager.MicroLibs[lib.key] + for k, lib := range kvSlice { + manager.SortedMicroLibs[k] = manager.MicroLibs[lib.key] } } func (manager *Manager) DisplayMicroLibs() { - manager.sortMicroLibs() - for i, lib := range manager.SortedMicroLibs { + if manager.SortedMicroLibs == nil { + manager.sortMicroLibs() + } - if lib.instance < len(manager.Unikernels) { - fmt.Printf("%d %s: %x - %x - %d\n", i, lib.name, lib.startAddr, lib.size, lib.instance) - } + for i, lib := range manager.SortedMicroLibs { + fmt.Printf("%d %s: %x - %x - %d\n", i, lib.name, lib.startAddr, lib.size, lib.instance) } } func (manager *Manager) PerformAlignement() { + var startValue uint64 = 0x106000 - //manager.Unikernels[0].Analyser.ElfLibs - - manager.sortMicroLibs() + var locationCnt = startValue commonMicroLibs := make([]*MicroLib, 0) - for _, lib := range manager.SortedMicroLibs { + + // Sort micro-libs per instance (usage) and per addresses (descending order) + if manager.SortedMicroLibs == nil { + manager.sortMicroLibs() + } + + // Update micro-libs mapping globally and per unikernels + for i, lib := range manager.SortedMicroLibs { if lib.instance == len(manager.Unikernels) { - lib.startAddr = startValue + // micro-libs common to all instances + lib.startAddr = locationCnt commonMicroLibs = append(commonMicroLibs, lib) - //fmt.Printf("%s -> 0x%x (0x%x) - 0x%x\n", lib.name, startValue, startValue, startValue+lib.size) - startValue += lib.size + locationCnt += lib.size } else if lib.instance > 1 { - //fmt.Printf("---%s -> 0x%x (0x%x) - 0x%x\n", lib.name, startValue, startValue, startValue+lib.size) - startValue = roundAddr(startValue) - for i, _ := range manager.Unikernels { - if manager.Unikernels[i].alignedLibs == nil { - // Init structure - manager.Unikernels[i].InitAlignment() + // micro-libs common to particular instances + if manager.SortedMicroLibs[i-1].instance == len(manager.Unikernels) { + // Add ukboot main after all common micro-libs + locationCnt = roundAddr(locationCnt, elf64analyser.PageSize) + ukbootMainLib := &MicroLib{ + name: ukbootMain, + startAddr: locationCnt, + size: 0, + instance: len(manager.Unikernels), + sectionSize: &SectionMicroLibs{}, } - manager.Unikernels[i].AddAlignedMicroLibs(startValue, lib) + commonMicroLibs = append(commonMicroLibs, ukbootMainLib) } - startValue += lib.size - //fmt.Printf("%s -> 0x%x (0x%x) - 0x%x\n", lib.name, startValue, roundAddr(startValue), startValue+lib.size) + + locationCnt = roundAddr(locationCnt, elf64analyser.PageSize) + for _, uk := range manager.Unikernels { + if uk.alignedLibs == nil { + uk.InitAlignment() + } + uk.AddAlignedMicroLibs(locationCnt, lib) + } + locationCnt += lib.size } else if lib.instance == 1 { - for i, _ := range manager.Unikernels { - manager.Unikernels[i].AddSingleMicroLibs(roundAddr(startValue), lib) + // micro-libs to only single instance + for _, uk := range manager.Unikernels { + uk.AddSingleMicroLibs(roundAddr(locationCnt, elf64analyser.PageSize), lib) } - //fmt.Printf("%s -> 0x%x (0x%x) - 0x%x\n", lib.name, startValue, roundAddr(startValue), startValue+lib.size) } } - // Find max value through unikernels - for i, _ := range manager.Unikernels { - manager.Unikernels[i].alignedLibs.AllCommonMicroLibs = commonMicroLibs - if startValue < manager.Unikernels[i].alignedLibs.startValueUk { - startValue = manager.Unikernels[i].alignedLibs.startValueUk - } - } + maxValSection := make(map[string]uint64, 3) + sections := []string{elf64core.RodataSection, elf64core.DataSection, elf64core.TbssSection, elf64core.BssSection} - fmt.Printf("END SECTIONS: 0x%x\n", roundAddr(startValue)) - - /*println(commonMicroLibs.String()) + // Find max location counter value through unikernels for _, uk := range manager.Unikernels { - println(uk.microLibsInstance.String()) - }*/ + + // Update the locationCnt by finding the maximum one from unikernel (the biggest size) + uk.alignedLibs.AllCommonMicroLibs = commonMicroLibs + if locationCnt < uk.alignedLibs.startValueUk { + locationCnt = uk.alignedLibs.startValueUk + } + + // Analyse sections to find the biggest section sizes (rodata, data, tbss, bss) + for _, section := range sections { + findMaxValue(section, uk, maxValSection) + } + } + + // Update the common lds file with new location counter + locationCnt = roundAddr(locationCnt, elf64analyser.PageSize) + linkerInfo := processLdsFile(locationCnt, maxValSection) + + // Use temporary variable to keep linkerInfo unchanged + linkerInfoGlobal := &LinkerInfo{ + ldsString: "", + rodataAddr: linkerInfo.rodataAddr, + dataAddr: linkerInfo.dataAddr, + bssAddr: linkerInfo.bssAddr, + } + // Redo a pass on micro-libs to align inner rodata, data and bss + for _, lib := range manager.SortedMicroLibs { + + if lib.instance > 1 { + // Update inner rodata location counter + lib.sectionSize.rodataAddr = linkerInfoGlobal.rodataAddr + linkerInfoGlobal.rodataAddr += roundAddr(lib.sectionSize.rodataSize, 32) + + // Update inner dataAddr location counter + lib.sectionSize.dataAddr = linkerInfoGlobal.dataAddr + linkerInfoGlobal.dataAddr += roundAddr(lib.sectionSize.dataSize, 32) + + // Update inner bssAddr location counter + lib.sectionSize.bssAddr = linkerInfoGlobal.bssAddr + linkerInfoGlobal.bssAddr += roundAddr(lib.sectionSize.bssSize, 32) + } + } + + // Update per unikernel + for _, uk := range manager.Unikernels { + uk.writeTextAlignment(startValue) + + // todo remove and replace per uk.buildpath + lib := strings.Replace(strings.Split(uk.BuildPath, "/")[5], "lib-", "", -1) + dst := "/Users/gaulthiergain/Desktop/memory_dedup/gcc/lds/common_optimized_app_dce_size/link64_" + lib + ".lds" + + uk.writeLdsToFile(dst, linkerInfo) + } + } -func roundAddr(value uint64) uint64 { - x := float64(value) - unit := float64(elf64analyser.PageSize) - return uint64(math.Round(x/unit+0.5) * unit) +func findMaxValue(section string, uk *Unikernel, maxValSection map[string]uint64) { + index := uk.ElfFile.IndexSections[section] + size := uk.ElfFile.SectionsTable.DataSect[index].Elf64section.Size + if val, ok := maxValSection[section]; ok { + if val < size { + maxValSection[section] = size + } + } else { + maxValSection[section] = size + } +} + +func roundAddr(v uint64, round uint64) uint64 { + return uint64(math.Round(float64(v/round))*float64(round)) + round } diff --git a/srcs/binarytool/ukManager/unikernels.go b/srcs/binarytool/ukManager/unikernels.go index d46ceae..b99b3eb 100644 --- a/srcs/binarytool/ukManager/unikernels.go +++ b/srcs/binarytool/ukManager/unikernels.go @@ -7,8 +7,10 @@ package ukManager import ( + "encoding/json" "fmt" "io/ioutil" + "os" "path/filepath" "strings" "tools/srcs/binarytool/elf64analyser" @@ -19,7 +21,6 @@ import ( const ( makefile = "Makefile" config = "config" - objExt = ".o" ldExt = ".ld.o" dbgExt = ".dbg" ) @@ -52,15 +53,37 @@ type Unikernel struct { Analyser *elf64analyser.ElfAnalyser alignedLibs *AlignedLibs + strBuilder strings.Builder } type AlignedLibs struct { startValueUk uint64 + startValueInit uint64 AllCommonMicroLibs []*MicroLib OnlyFewMicroLibs []*MicroLib SingleMicroLibs []*MicroLib } +func ReadJsonFile(path string) ([]*Unikernel, error) { + jsonFile, err := os.Open(path) + if err != nil { + return nil, err + } + defer jsonFile.Close() + byteValue, _ := ioutil.ReadAll(jsonFile) + unikernels := new(Unikernels) + if err := json.Unmarshal(byteValue, unikernels); err != nil { + return nil, err + } + + uks := make([]*Unikernel, len(unikernels.Unikernel)) + for i, _ := range unikernels.Unikernel { + uks[i] = &unikernels.Unikernel[i] + } + unikernels = nil + return uks, nil +} + func parseFile(path, name string) (*elf64core.ELF64File, error) { var elfFile *elf64core.ELF64File elfFile = new(elf64core.ELF64File) @@ -118,7 +141,7 @@ func (uk *Unikernel) GetFiles() error { } if len(uk.Kernel) > 0 { - u.PrintInfo("Use specified ELF file: " + uk.ElfFile.Name) + u.PrintInfo("Use specified ELF file: " + uk.ElfFile.Name + "(" + uk.BuildPath + ")") } else { u.PrintInfo("Use ELF file found in build folder: " + uk.ElfFile.Name) } @@ -171,35 +194,98 @@ func (uk *Unikernel) DisplayElfInfo() { func (uk *Unikernel) InitAlignment() { uk.alignedLibs = &AlignedLibs{ startValueUk: 0, - AllCommonMicroLibs: make([]*MicroLib, 0), //todo update with fixed entry + startValueInit: 0, + AllCommonMicroLibs: make([]*MicroLib, 0), OnlyFewMicroLibs: make([]*MicroLib, 0), SingleMicroLibs: make([]*MicroLib, 0), } } func (uk *Unikernel) AddAlignedMicroLibs(startValue uint64, lib *MicroLib) { - - for _, ukLibs := range uk.Analyser.ElfLibs { - if ukLibs.Name == lib.name { - fmt.Printf("%s -> 0x%x - 0x%x\n", lib.name, startValue, startValue+lib.size) - uk.alignedLibs.OnlyFewMicroLibs = append(uk.alignedLibs.SingleMicroLibs, lib) - break - } + if _, ok := uk.Analyser.MapElfLibs[lib.name]; ok { + lib.startAddr = startValue + uk.alignedLibs.OnlyFewMicroLibs = append(uk.alignedLibs.OnlyFewMicroLibs, lib) } } func (uk *Unikernel) AddSingleMicroLibs(startValue uint64, lib *MicroLib) { + if _, ok := uk.Analyser.MapElfLibs[lib.name]; ok { - for _, ukLibs := range uk.Analyser.ElfLibs { - if ukLibs.Name == lib.name { - - uk.alignedLibs.SingleMicroLibs = append(uk.alignedLibs.SingleMicroLibs, lib) - if uk.alignedLibs.startValueUk == 0 { - uk.alignedLibs.startValueUk = startValue - } - fmt.Printf("%s -> 0x%x - 0x%x\n", lib.name, uk.alignedLibs.startValueUk, uk.alignedLibs.startValueUk+lib.size) - uk.alignedLibs.startValueUk += lib.size - break + uk.alignedLibs.SingleMicroLibs = append(uk.alignedLibs.SingleMicroLibs, lib) + if uk.alignedLibs.startValueInit == 0 { + uk.alignedLibs.startValueInit = startValue + uk.alignedLibs.startValueUk = startValue } + uk.alignedLibs.startValueUk += lib.size + } +} + +func (uk *Unikernel) writeTextAlignment(startValue uint64) { + + uk.strBuilder = strings.Builder{} + uk.strBuilder.WriteString("SECTIONS\n{\n") + uk.strBuilder.WriteString(fmt.Sprintf(" . = 0x%x;\n", startValue)) + for _, lib := range uk.alignedLibs.AllCommonMicroLibs { + uk.strBuilder.WriteString(fmt.Sprintf(" .text.%s : {\n\t %s(.text);\n }\n", strings.Replace(lib.name, ldExt, "", -1), lib.name)) + } + + for _, lib := range uk.alignedLibs.OnlyFewMicroLibs { + uk.strBuilder.WriteString(fmt.Sprintf(" .text.%s 0x%x: {\n\t %s(.text);\n }\n", strings.Replace(lib.name, ldExt, "", -1), lib.startAddr, lib.name)) + } + + uk.strBuilder.WriteString(fmt.Sprintf(" . = 0x%x;\n", uk.alignedLibs.startValueInit)) + + for _, lib := range uk.alignedLibs.SingleMicroLibs { + uk.strBuilder.WriteString(fmt.Sprintf(" .text.%s : {\n\t %s(.text);\n }\n", strings.Replace(lib.name, ldExt, "", -1), lib.name)) + } + + uk.strBuilder.WriteString("}\n") +} + +func (uk *Unikernel) sectionsObjs(linkerInfo LinkerInfo) string { + + // 0: rodata, 1: data, 2: bss + strBuilder := [3]strings.Builder{} + for _, obj := range uk.alignedLibs.AllCommonMicroLibs { + if obj.name == ukbootMain { + // Ignore ukbootMain + continue + } + strBuilder[0].WriteString(fmt.Sprintf("%s (.rodata);\n", obj.name)) + strBuilder[1].WriteString(fmt.Sprintf("%s (.data);\n", obj.name)) + strBuilder[2].WriteString(fmt.Sprintf("%s (.bss);\n", obj.name)) + } + + for _, obj := range uk.alignedLibs.OnlyFewMicroLibs { + strBuilder[0].WriteString(fmt.Sprintf(". = ABSOLUTE(0x%x);\n%s (.rodata);\n", obj.sectionSize.rodataAddr, obj.name)) + strBuilder[1].WriteString(fmt.Sprintf(". = ABSOLUTE(0x%x);\n%s (.data);\n", obj.sectionSize.dataAddr, obj.name)) + strBuilder[2].WriteString(fmt.Sprintf(". = ABSOLUTE(0x%x);\n%s (.bss);\n", obj.sectionSize.bssAddr, obj.name)) + } + + // Add ukbootMain before single microlibs + strBuilder[0].WriteString(fmt.Sprintf("%s (.rodata);\n", ukbootMain)) + strBuilder[1].WriteString(fmt.Sprintf("%s (.data);\n", ukbootMain)) + strBuilder[2].WriteString(fmt.Sprintf("%s (.bss);\n", ukbootMain)) + + for _, obj := range uk.alignedLibs.SingleMicroLibs { + strBuilder[0].WriteString(fmt.Sprintf("%s (.rodata);\n", obj.name)) + strBuilder[1].WriteString(fmt.Sprintf("%s (.data);\n", obj.name)) + strBuilder[2].WriteString(fmt.Sprintf("%s (.bss);\n", obj.name)) + } + + arrLoc := []string{inner_rodata, inner_data, inner_bss} + for i, builder := range strBuilder { + linkerInfo.ldsString = strings.Replace(linkerInfo.ldsString, arrLoc[i], builder.String(), -1) + } + + return linkerInfo.ldsString +} + +func (uk *Unikernel) writeLdsToFile(filename string, linkerInfo LinkerInfo) { + + // Replace rodata, data,bss from object section + linkerInfo.ldsString = uk.sectionsObjs(linkerInfo) + if err := os.WriteFile(filename, []byte(uk.strBuilder.String()+linkerInfo.ldsString), 0644); err != nil { + u.PrintErr(err) } }