gaulthiergain-tools/srcs/binarytool/ukManager/manager.go

238 lines
6.8 KiB
Go
Raw Normal View History

2021-12-07 10:24:33 +01:00
package ukManager
2021-12-07 21:33:17 +01:00
import (
"fmt"
"math"
"sort"
2021-12-10 20:00:22 +01:00
"strings"
2021-12-07 21:33:17 +01:00
"tools/srcs/binarytool/elf64analyser"
2021-12-10 20:00:22 +01:00
"tools/srcs/binarytool/elf64core"
2021-12-07 21:33:17 +01:00
u "tools/srcs/common"
)
2021-12-10 20:00:22 +01:00
const ukbootMain = "libukboot_main.ld.o"
2021-12-07 10:24:33 +01:00
type Manager struct {
2021-12-10 20:00:22 +01:00
Unikernels []*Unikernel
2021-12-07 21:33:17 +01:00
MicroLibs map[string]*MicroLib
SortedMicroLibs []*MicroLib //Used for the display
}
type MicroLib struct {
name string
startAddr uint64
size uint64
instance int
2021-12-10 20:00:22 +01:00
sectionSize *SectionMicroLibs
2021-12-07 21:33:17 +01:00
}
type SectionMicroLibs struct {
rodataSize uint64
dataSize uint64
2021-12-10 20:00:22 +01:00
bssSize uint64
rodataAddr uint64
dataAddr uint64
bssAddr uint64
2021-12-07 10:24:33 +01:00
}
2021-12-07 21:33:17 +01:00
func (manager *Manager) ComputeAlignment(unikernel Unikernel) {
for _, libs := range unikernel.Analyser.ElfLibs {
2021-12-10 20:00:22 +01:00
// Ignore ukbootMain to place it to specific position
if libs.Name == ukbootMain {
continue
}
// Add microlib to a global map per instance
2021-12-07 21:33:17 +01:00
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
2021-12-10 20:00:22 +01:00
manager.MicroLibs[libs.Name].sectionSize.rodataSize = libs.RodataSize
manager.MicroLibs[libs.Name].sectionSize.dataSize = libs.DataSize
manager.MicroLibs[libs.Name].sectionSize.bssSize = libs.BssSize
2021-12-07 21:33:17 +01:00
}
}
manager.MicroLibs[libs.Name].instance += 1
} else {
mlib := &MicroLib{
name: libs.Name,
startAddr: libs.StartAddr,
size: libs.Size,
instance: 1,
2021-12-10 20:00:22 +01:00
sectionSize: &SectionMicroLibs{
rodataSize: libs.RodataSize,
dataSize: libs.DataSize,
bssSize: libs.BssSize,
},
2021-12-07 21:33:17 +01:00
}
manager.MicroLibs[libs.Name] = mlib
}
}
2021-12-07 10:24:33 +01:00
}
2021-12-07 21:33:17 +01:00
func (manager *Manager) sortMicroLibs() {
type kv struct {
key string
instance int
addr uint64
}
i := 0
var kvSlice = make([]kv, len(manager.MicroLibs))
for k, v := range manager.MicroLibs {
kvSlice[i] = kv{k, v.instance, v.startAddr}
i++
}
sort.Slice(kvSlice, func(i, j int) bool {
if kvSlice[i].instance != kvSlice[j].instance {
return kvSlice[i].instance > kvSlice[j].instance
}
return kvSlice[i].addr < kvSlice[j].addr
})
manager.SortedMicroLibs = make([]*MicroLib, len(manager.MicroLibs))
2021-12-10 20:00:22 +01:00
for k, lib := range kvSlice {
manager.SortedMicroLibs[k] = manager.MicroLibs[lib.key]
2021-12-07 21:33:17 +01:00
}
}
func (manager *Manager) DisplayMicroLibs() {
2021-12-10 20:00:22 +01:00
if manager.SortedMicroLibs == nil {
manager.sortMicroLibs()
}
2021-12-07 21:33:17 +01:00
2021-12-10 20:00:22 +01:00
for i, lib := range manager.SortedMicroLibs {
fmt.Printf("%d %s: %x - %x - %d\n", i, lib.name, lib.startAddr, lib.size, lib.instance)
2021-12-07 21:33:17 +01:00
}
}
func (manager *Manager) PerformAlignement() {
2021-12-10 20:00:22 +01:00
var startValue uint64 = 0x106000
var locationCnt = startValue
2021-12-07 21:33:17 +01:00
commonMicroLibs := make([]*MicroLib, 0)
2021-12-10 20:00:22 +01:00
// 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 {
2021-12-07 21:33:17 +01:00
if lib.instance == len(manager.Unikernels) {
2021-12-10 20:00:22 +01:00
// micro-libs common to all instances
lib.startAddr = locationCnt
2021-12-07 21:33:17 +01:00
commonMicroLibs = append(commonMicroLibs, lib)
2021-12-10 20:00:22 +01:00
locationCnt += lib.size
2021-12-07 21:33:17 +01:00
} else if lib.instance > 1 {
2021-12-10 20:00:22 +01:00
// 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{},
2021-12-07 21:33:17 +01:00
}
2021-12-10 20:00:22 +01:00
commonMicroLibs = append(commonMicroLibs, ukbootMainLib)
2021-12-07 21:33:17 +01:00
}
2021-12-10 20:00:22 +01:00
locationCnt = roundAddr(locationCnt, elf64analyser.PageSize)
for _, uk := range manager.Unikernels {
if uk.alignedLibs == nil {
uk.InitAlignment()
}
uk.AddAlignedMicroLibs(locationCnt, lib)
}
locationCnt += lib.size
2021-12-07 21:33:17 +01:00
} else if lib.instance == 1 {
2021-12-10 20:00:22 +01:00
// micro-libs to only single instance
for _, uk := range manager.Unikernels {
uk.AddSingleMicroLibs(roundAddr(locationCnt, elf64analyser.PageSize), lib)
2021-12-07 21:33:17 +01:00
}
}
}
2021-12-10 20:00:22 +01:00
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
2021-12-07 21:33:17 +01:00
}
2021-12-10 20:00:22 +01:00
// 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,
2021-12-07 21:33:17 +01:00
}
2021-12-10 20:00:22 +01:00
// 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)
2021-12-07 21:33:17 +01:00
2021-12-10 20:00:22 +01:00
// Update inner bssAddr location counter
lib.sectionSize.bssAddr = linkerInfoGlobal.bssAddr
linkerInfoGlobal.bssAddr += roundAddr(lib.sectionSize.bssSize, 32)
}
}
2021-12-07 21:33:17 +01:00
2021-12-10 20:00:22 +01:00
// Update per unikernel
2021-12-07 21:33:17 +01:00
for _, uk := range manager.Unikernels {
2021-12-10 20:00:22 +01:00
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 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
}
2021-12-07 21:33:17 +01:00
}
2021-12-07 10:24:33 +01:00
2021-12-10 20:00:22 +01:00
func roundAddr(v uint64, round uint64) uint64 {
return uint64(math.Round(float64(v/round))*float64(round)) + round
2021-12-07 10:24:33 +01:00
}