Update
This commit is contained in:
parent
fa9c5399a9
commit
75162aa119
8 changed files with 468 additions and 130 deletions
86
lds/common.ld
Normal file
86
lds/common.ld
Normal 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) }
|
||||
}
|
|
@ -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++
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
103
srcs/binarytool/ukManager/elf_linker.go
Normal file
103
srcs/binarytool/ukManager/elf_linker.go
Normal 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
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue