This commit is contained in:
Gaulthier Gain 2021-12-10 20:00:22 +01:00
parent fa9c5399a9
commit 75162aa119
8 changed files with 468 additions and 130 deletions

86
lds/common.ld Normal file
View file

@ -0,0 +1,86 @@
SECTIONS
{
. = 0x100000;
_text = .;
.text :
{
KEEP (*(.data.boot))
*(.text.boot)
*(.text)
*(.text.*) /* uncomment it to dissagregate functions */
}
<END_TEXT_REPLACE_LOCATION>
_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_INIT_REPLACE_LOCATION> uk_inittab_start = .; .uk_inittab : { KEEP(*(SORT_BY_NAME(.uk_inittab[1-6][0-9]))) } uk_inittab_end = .;
<RODATA_REPLACE_LOCATION>
. = ALIGN((1 << 12));
_rodata = .;
.rodata :
{
<INNER_RODATA>
*(.rodata)
*(.rodata.*)
}
<ERODATA_REPLACE_LOCATION>
_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 = .;
<DATA_REPLACE_LOCATION>
. = ALIGN((1 << 12));
_data = .;
.data :
{
<INNER_DATA>
*(.data)
*(.data.*)
}
<EDATA_REPLACE_LOCATION>
_edata = .;
. = ALIGN((1 << 12));
<BSS_REPLACE_LOCATION>
__bss_start = .;
.bss :
{
<INNER_BSS>
*(.bss)
*(.bss.*)
*(COMMON)
. = ALIGN((1 << 12));
}
<TBSS_REPLACE_LOCATION>
.tbss : { *(.tbss) *(.tbss.*) *(.gnu.linkonce.tb.*) . = ALIGN(0x8); } _tls_end = . + SIZEOF(.tbss);
<INTRSTACK_REPLACE_LOCATION>
.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) }
}

View file

@ -7,8 +7,6 @@
package elf64analyser package elf64analyser
import ( import (
"crypto/sha256"
"encoding/hex"
"fmt" "fmt"
"os" "os"
"sort" "sort"
@ -21,6 +19,7 @@ import (
type ElfAnalyser struct { type ElfAnalyser struct {
ElfLibs []ElfLibs ElfLibs []ElfLibs
ElfPage []*ElfPage ElfPage []*ElfPage
MapElfLibs map[string]*ElfLibs
} }
type ElfLibs struct { type ElfLibs struct {
@ -29,6 +28,10 @@ type ElfLibs struct {
EndAddr uint64 EndAddr uint64
Size uint64 Size uint64
NbSymbols int NbSymbols int
RodataSize uint64
DataSize uint64
BssSize uint64
} }
func (analyser *ElfAnalyser) DisplayMapping() { func (analyser *ElfAnalyser) DisplayMapping() {
@ -151,30 +154,11 @@ func compareFunctions(elf *elf64core.ELF64File, obj *elf64core.ELF64File) (uint6
elfFuncsAll[len(elfFuncsAll)-1].Addr, len(elfFuncsAll) elfFuncsAll[len(elfFuncsAll)-1].Addr, len(elfFuncsAll)
} }
func (analyser *ElfAnalyser) InspectMapping(elf *elf64core.ELF64File, objs ...interface{}) { func getSectionSize(name string, obj *elf64core.ELF64File) uint64 {
if index, ok := obj.IndexSections[name]; ok {
if len(objs) == 0 { return obj.SectionsTable.DataSect[index].Elf64section.Size
return
} }
return 0
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
})
} }
func (analyser *ElfAnalyser) InspectMappingList(elf *elf64core.ELF64File, func (analyser *ElfAnalyser) InspectMappingList(elf *elf64core.ELF64File,
@ -184,16 +168,25 @@ func (analyser *ElfAnalyser) InspectMappingList(elf *elf64core.ELF64File,
return return
} }
analyser.ElfLibs = make([]ElfLibs, 0) analyser.ElfLibs = make([]ElfLibs, len(objs))
for _, obj := range objs { analyser.MapElfLibs = make(map[string]*ElfLibs, len(analyser.ElfLibs))
for i, obj := range objs {
start, end, nbSymbols := compareFunctions(elf, obj) start, end, nbSymbols := compareFunctions(elf, obj)
analyser.ElfLibs = append(analyser.ElfLibs, ElfLibs{ lib := ElfLibs{
Name: obj.Name, Name: obj.Name,
StartAddr: start, StartAddr: start,
EndAddr: end, EndAddr: end,
Size: end - start, Size: end - start,
NbSymbols: nbSymbols, 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. // 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) { func (analyser *ElfAnalyser) SplitIntoPagesBySection(elfFile *elf64core.ELF64File, sectionName string) {
if len(analyser.ElfPage) == 0 { if len(analyser.ElfPage) == 0 {
@ -211,8 +205,7 @@ func (analyser *ElfAnalyser) SplitIntoPagesBySection(elfFile *elf64core.ELF64Fil
if strings.Contains(sectionName, elf64core.TextSection) { if strings.Contains(sectionName, elf64core.TextSection) {
// An ELF might have several text sections // An ELF might have several text sections
for _, indexSection := range elfFile.TextSectionIndex { for _, indexSection := range elfFile.TextSectionIndex {
sectionName := elfFile.SectionsTable.DataSect[indexSection].Name analyser.computePage(elfFile, elfFile.SectionsTable.DataSect[indexSection].Name, indexSection)
analyser.computePage(elfFile, sectionName, indexSection)
} }
} else if indexSection, ok := elfFile.IndexSections[sectionName]; ok { } else if indexSection, ok := elfFile.IndexSections[sectionName]; ok {
analyser.computePage(elfFile, sectionName, indexSection) 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 { func CreateNewPage(startAddress uint64, k int, raw []byte) *ElfPage {
byteArray := make([]byte, PageSize) byteArray := make([]byte, PageSize)
b := raw b := raw
@ -253,3 +247,4 @@ func (analyser *ElfAnalyser) computePage(elfFile *elf64core.ELF64File, section s
k++ k++
} }
} }
*/

View file

@ -54,12 +54,6 @@ func (p *ElfPage) pageContentToString() string {
func (p *ElfPage) displayPageContent(mw io.Writer) { 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 { for i, entry := range p.contentByteArray {
if i > 0 && i%4 == 0 { if i > 0 && i%4 == 0 {

View file

@ -37,14 +37,14 @@ func RunBinaryAnalyser(homeDir string) {
manager := new(ukManager.Manager) manager := new(ukManager.Manager)
manager.MicroLibs = make(map[string]*ukManager.MicroLib) manager.MicroLibs = make(map[string]*ukManager.MicroLib)
if len(*args.StringArg[listArg]) > 0 { 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 mapping := false
if *args.BoolArg[mappingArg] { if *args.BoolArg[mappingArg] {
mapping = true mapping = true
} }
list := strings.Split(*args.StringArg[listArg], ",") list := strings.Split(*args.StringArg[listArg], ",")
for i, arg := range list { for i, arg := range list {
manager.Unikernels[i] = ukManager.Unikernel{ manager.Unikernels[i] = &ukManager.Unikernel{
BuildPath: arg, BuildPath: arg,
DisplayMapping: mapping, DisplayMapping: mapping,
} }
@ -62,10 +62,9 @@ func RunBinaryAnalyser(homeDir string) {
var comparison elf64analyser.ComparisonElf var comparison elf64analyser.ComparisonElf
comparison.GroupFileSegment = make([]*elf64analyser.ElfFileSegment, 0) 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.Analyser = new(elf64analyser.ElfAnalyser)
uk := manager.Unikernels[i]
if len(uk.BuildPath) > 0 { if len(uk.BuildPath) > 0 {
if uk.BuildPath[len(uk.BuildPath)-1] != os.PathSeparator { if uk.BuildPath[len(uk.BuildPath)-1] != os.PathSeparator {
uk.BuildPath += u.SEP uk.BuildPath += u.SEP
@ -104,7 +103,7 @@ func RunBinaryAnalyser(homeDir string) {
uk.Analyser.FindSectionByAddress(uk.ElfFile, uk.FindSectionByAddress) uk.Analyser.FindSectionByAddress(uk.ElfFile, uk.FindSectionByAddress)
} }
manager.ComputeAlignment(uk) manager.ComputeAlignment(*uk)
/*if uk.CompareGroup > 0 { /*if uk.CompareGroup > 0 {

View file

@ -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 = "<END_TEXT_REPLACE_LOCATION>"
rodata_location = "<RODATA_REPLACE_LOCATION>"
data_location = "<DATA_REPLACE_LOCATION>"
erodata_location = "<ERODATA_REPLACE_LOCATION>"
edata_location = "<EDATA_REPLACE_LOCATION>"
bss_location = "<BSS_REPLACE_LOCATION>"
tbss_location = "<TBSS_REPLACE_LOCATION>"
intrstack_location = "<INTRSTACK_REPLACE_LOCATION>"
ukinit_location = "<UK_INIT_REPLACE_LOCATION>"
inner_rodata = "<INNER_RODATA>"
inner_data = "<INNER_DATA>"
inner_bss = "<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
}

View file

@ -7,27 +7,9 @@
package ukManager package ukManager
import ( import (
"encoding/json"
"io/ioutil"
"os"
"strings" "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 { func stringInSlice(name string, plats []string) bool {
for _, plat := range plats { for _, plat := range plats {
if strings.Contains(name, plat) { if strings.Contains(name, plat) {

View file

@ -4,12 +4,16 @@ import (
"fmt" "fmt"
"math" "math"
"sort" "sort"
"strings"
"tools/srcs/binarytool/elf64analyser" "tools/srcs/binarytool/elf64analyser"
"tools/srcs/binarytool/elf64core"
u "tools/srcs/common" u "tools/srcs/common"
) )
const ukbootMain = "libukboot_main.ld.o"
type Manager struct { type Manager struct {
Unikernels []Unikernel Unikernels []*Unikernel
MicroLibs map[string]*MicroLib MicroLibs map[string]*MicroLib
SortedMicroLibs []*MicroLib //Used for the display SortedMicroLibs []*MicroLib //Used for the display
} }
@ -19,24 +23,38 @@ type MicroLib struct {
startAddr uint64 startAddr uint64
size uint64 size uint64
instance int instance int
sectionSize SectionMicroLibs sectionSize *SectionMicroLibs
} }
type SectionMicroLibs struct { type SectionMicroLibs struct {
rodataSize uint64 rodataSize uint64
dataSize uint64 dataSize uint64
BssSize uint64 bssSize uint64
rodataAddr uint64
dataAddr uint64
bssAddr uint64
} }
func (manager *Manager) ComputeAlignment(unikernel Unikernel) { func (manager *Manager) ComputeAlignment(unikernel Unikernel) {
for _, libs := range unikernel.Analyser.ElfLibs { 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 val, ok := manager.MicroLibs[libs.Name]; ok {
if manager.MicroLibs[libs.Name].size != libs.Size { 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)) //u.PrintWarning(fmt.Sprintf("Different size between %s (0x%x) (0x%x)", libs.Name, libs.Size, val.size))
if val.size < libs.Size { if val.size < libs.Size {
u.PrintWarning(fmt.Sprintf("Bigger size found %s (0x%x) > (0x%x)", libs.Name, libs.Size, val.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].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 manager.MicroLibs[libs.Name].instance += 1
@ -46,6 +64,11 @@ func (manager *Manager) ComputeAlignment(unikernel Unikernel) {
startAddr: libs.StartAddr, startAddr: libs.StartAddr,
size: libs.Size, size: libs.Size,
instance: 1, instance: 1,
sectionSize: &SectionMicroLibs{
rodataSize: libs.RodataSize,
dataSize: libs.DataSize,
bssSize: libs.BssSize,
},
} }
manager.MicroLibs[libs.Name] = mlib manager.MicroLibs[libs.Name] = mlib
} }
@ -58,7 +81,6 @@ func (manager *Manager) sortMicroLibs() {
instance int instance int
addr uint64 addr uint64
} }
i := 0 i := 0
var kvSlice = make([]kv, len(manager.MicroLibs)) var kvSlice = make([]kv, len(manager.MicroLibs))
for k, v := range manager.MicroLibs { for k, v := range manager.MicroLibs {
@ -74,71 +96,142 @@ func (manager *Manager) sortMicroLibs() {
}) })
manager.SortedMicroLibs = make([]*MicroLib, len(manager.MicroLibs)) manager.SortedMicroLibs = make([]*MicroLib, len(manager.MicroLibs))
for i, lib := range kvSlice { for k, lib := range kvSlice {
manager.SortedMicroLibs[i] = manager.MicroLibs[lib.key] manager.SortedMicroLibs[k] = manager.MicroLibs[lib.key]
} }
} }
func (manager *Manager) DisplayMicroLibs() { func (manager *Manager) DisplayMicroLibs() {
if manager.SortedMicroLibs == nil {
manager.sortMicroLibs() manager.sortMicroLibs()
for i, lib := range manager.SortedMicroLibs {
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() { func (manager *Manager) PerformAlignement() {
var startValue uint64 = 0x106000 var startValue uint64 = 0x106000
//manager.Unikernels[0].Analyser.ElfLibs var locationCnt = startValue
manager.sortMicroLibs()
commonMicroLibs := make([]*MicroLib, 0) 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) { if lib.instance == len(manager.Unikernels) {
lib.startAddr = startValue // micro-libs common to all instances
lib.startAddr = locationCnt
commonMicroLibs = append(commonMicroLibs, lib) commonMicroLibs = append(commonMicroLibs, lib)
//fmt.Printf("%s -> 0x%x (0x%x) - 0x%x\n", lib.name, startValue, startValue, startValue+lib.size) locationCnt += lib.size
startValue += lib.size
} else if lib.instance > 1 { } else if lib.instance > 1 {
//fmt.Printf("---%s -> 0x%x (0x%x) - 0x%x\n", lib.name, startValue, startValue, startValue+lib.size) // micro-libs common to particular instances
startValue = roundAddr(startValue) if manager.SortedMicroLibs[i-1].instance == len(manager.Unikernels) {
for i, _ := range manager.Unikernels { // Add ukboot main after all common micro-libs
if manager.Unikernels[i].alignedLibs == nil { locationCnt = roundAddr(locationCnt, elf64analyser.PageSize)
// Init structure ukbootMainLib := &MicroLib{
manager.Unikernels[i].InitAlignment() name: ukbootMain,
} startAddr: locationCnt,
manager.Unikernels[i].AddAlignedMicroLibs(startValue, lib) size: 0,
} instance: len(manager.Unikernels),
startValue += lib.size sectionSize: &SectionMicroLibs{},
//fmt.Printf("%s -> 0x%x (0x%x) - 0x%x\n", lib.name, startValue, roundAddr(startValue), startValue+lib.size)
} else if lib.instance == 1 {
for i, _ := range manager.Unikernels {
manager.Unikernels[i].AddSingleMicroLibs(roundAddr(startValue), lib)
}
//fmt.Printf("%s -> 0x%x (0x%x) - 0x%x\n", lib.name, startValue, roundAddr(startValue), startValue+lib.size)
} }
commonMicroLibs = append(commonMicroLibs, ukbootMainLib)
} }
// Find max value through unikernels locationCnt = roundAddr(locationCnt, elf64analyser.PageSize)
for i, _ := range manager.Unikernels {
manager.Unikernels[i].alignedLibs.AllCommonMicroLibs = commonMicroLibs
if startValue < manager.Unikernels[i].alignedLibs.startValueUk {
startValue = manager.Unikernels[i].alignedLibs.startValueUk
}
}
fmt.Printf("END SECTIONS: 0x%x\n", roundAddr(startValue))
/*println(commonMicroLibs.String())
for _, uk := range manager.Unikernels { for _, uk := range manager.Unikernels {
println(uk.microLibsInstance.String()) if uk.alignedLibs == nil {
}*/ uk.InitAlignment()
}
uk.AddAlignedMicroLibs(locationCnt, lib)
}
locationCnt += lib.size
} else if lib.instance == 1 {
// micro-libs to only single instance
for _, uk := range manager.Unikernels {
uk.AddSingleMicroLibs(roundAddr(locationCnt, elf64analyser.PageSize), lib)
}
}
}
maxValSection := make(map[string]uint64, 3)
sections := []string{elf64core.RodataSection, elf64core.DataSection, elf64core.TbssSection, elf64core.BssSection}
// Find max location counter value through unikernels
for _, uk := range manager.Unikernels {
// 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 { func findMaxValue(section string, uk *Unikernel, maxValSection map[string]uint64) {
x := float64(value) index := uk.ElfFile.IndexSections[section]
unit := float64(elf64analyser.PageSize) size := uk.ElfFile.SectionsTable.DataSect[index].Elf64section.Size
return uint64(math.Round(x/unit+0.5) * unit) 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
} }

View file

@ -7,8 +7,10 @@
package ukManager package ukManager
import ( import (
"encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os"
"path/filepath" "path/filepath"
"strings" "strings"
"tools/srcs/binarytool/elf64analyser" "tools/srcs/binarytool/elf64analyser"
@ -19,7 +21,6 @@ import (
const ( const (
makefile = "Makefile" makefile = "Makefile"
config = "config" config = "config"
objExt = ".o"
ldExt = ".ld.o" ldExt = ".ld.o"
dbgExt = ".dbg" dbgExt = ".dbg"
) )
@ -52,15 +53,37 @@ type Unikernel struct {
Analyser *elf64analyser.ElfAnalyser Analyser *elf64analyser.ElfAnalyser
alignedLibs *AlignedLibs alignedLibs *AlignedLibs
strBuilder strings.Builder
} }
type AlignedLibs struct { type AlignedLibs struct {
startValueUk uint64 startValueUk uint64
startValueInit uint64
AllCommonMicroLibs []*MicroLib AllCommonMicroLibs []*MicroLib
OnlyFewMicroLibs []*MicroLib OnlyFewMicroLibs []*MicroLib
SingleMicroLibs []*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) { func parseFile(path, name string) (*elf64core.ELF64File, error) {
var elfFile *elf64core.ELF64File var elfFile *elf64core.ELF64File
elfFile = new(elf64core.ELF64File) elfFile = new(elf64core.ELF64File)
@ -118,7 +141,7 @@ func (uk *Unikernel) GetFiles() error {
} }
if len(uk.Kernel) > 0 { 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 { } else {
u.PrintInfo("Use ELF file found in build folder: " + uk.ElfFile.Name) u.PrintInfo("Use ELF file found in build folder: " + uk.ElfFile.Name)
} }
@ -171,35 +194,98 @@ func (uk *Unikernel) DisplayElfInfo() {
func (uk *Unikernel) InitAlignment() { func (uk *Unikernel) InitAlignment() {
uk.alignedLibs = &AlignedLibs{ uk.alignedLibs = &AlignedLibs{
startValueUk: 0, startValueUk: 0,
AllCommonMicroLibs: make([]*MicroLib, 0), //todo update with fixed entry startValueInit: 0,
AllCommonMicroLibs: make([]*MicroLib, 0),
OnlyFewMicroLibs: make([]*MicroLib, 0), OnlyFewMicroLibs: make([]*MicroLib, 0),
SingleMicroLibs: make([]*MicroLib, 0), SingleMicroLibs: make([]*MicroLib, 0),
} }
} }
func (uk *Unikernel) AddAlignedMicroLibs(startValue uint64, lib *MicroLib) { func (uk *Unikernel) AddAlignedMicroLibs(startValue uint64, lib *MicroLib) {
if _, ok := uk.Analyser.MapElfLibs[lib.name]; ok {
for _, ukLibs := range uk.Analyser.ElfLibs { lib.startAddr = startValue
if ukLibs.Name == lib.name { uk.alignedLibs.OnlyFewMicroLibs = append(uk.alignedLibs.OnlyFewMicroLibs, lib)
fmt.Printf("%s -> 0x%x - 0x%x\n", lib.name, startValue, startValue+lib.size)
uk.alignedLibs.OnlyFewMicroLibs = append(uk.alignedLibs.SingleMicroLibs, lib)
break
}
} }
} }
func (uk *Unikernel) AddSingleMicroLibs(startValue uint64, lib *MicroLib) { 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) uk.alignedLibs.SingleMicroLibs = append(uk.alignedLibs.SingleMicroLibs, lib)
if uk.alignedLibs.startValueUk == 0 { if uk.alignedLibs.startValueInit == 0 {
uk.alignedLibs.startValueInit = startValue
uk.alignedLibs.startValueUk = startValue 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 uk.alignedLibs.startValueUk += lib.size
break }
} }
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)
} }
} }