aboutsummaryrefslogtreecommitdiffhomepage
path: root/builder/sizes.go
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2023-03-06 01:54:12 +0100
committerRon Evans <[email protected]>2023-03-08 07:09:46 +0100
commit3701e6eac1774c96ef221de4644abbb4d1fa1f61 (patch)
treec33bbf2680e5b3d6962ee946b61c18930f815353 /builder/sizes.go
parent0463d348875f6ca4588115baabdc020ebbc3e775 (diff)
downloadtinygo-3701e6eac1774c96ef221de4644abbb4d1fa1f61.tar.gz
tinygo-3701e6eac1774c96ef221de4644abbb4d1fa1f61.zip
compiler: account for alignment with -size=full
Diffstat (limited to 'builder/sizes.go')
-rw-r--r--builder/sizes.go61
1 files changed, 50 insertions, 11 deletions
diff --git a/builder/sizes.go b/builder/sizes.go
index 2e3d22f39..caa3ca33f 100644
--- a/builder/sizes.go
+++ b/builder/sizes.go
@@ -75,6 +75,7 @@ func (ps *packageSize) RAM() uint64 {
type addressLine struct {
Address uint64
Length uint64 // length of this chunk
+ Align uint64 // (maximum) alignment of this line
File string // file path as stored in DWARF
IsVariable bool // true if this is a variable (or constant), false if it is code
}
@@ -86,6 +87,7 @@ type memorySection struct {
Type memoryType
Address uint64
Size uint64
+ Align uint64
}
type memoryType int
@@ -123,7 +125,7 @@ var (
// readProgramSizeFromDWARF reads the source location for each line of code and
// each variable in the program, as far as this is stored in the DWARF debug
// information.
-func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset uint64, skipTombstone bool) ([]addressLine, error) {
+func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset, codeAlignment uint64, skipTombstone bool) ([]addressLine, error) {
r := data.Reader()
var lines []*dwarf.LineFile
var addresses []addressLine
@@ -195,6 +197,7 @@ func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset uint64, skipTombstone
line := addressLine{
Address: prevLineEntry.Address + codeOffset,
Length: lineEntry.Address - prevLineEntry.Address,
+ Align: codeAlignment,
File: prevLineEntry.File.Name,
}
if line.Length != 0 {
@@ -232,9 +235,16 @@ func readProgramSizeFromDWARF(data *dwarf.Data, codeOffset uint64, skipTombstone
return nil, err
}
+ // Read alignment, if it's stored as part of the debug information.
+ var alignment uint64
+ if attr := e.AttrField(dwarf.AttrAlignment); attr != nil {
+ alignment = uint64(attr.Val.(int64))
+ }
+
addresses = append(addresses, addressLine{
Address: addr,
Length: uint64(typ.Size()),
+ Align: alignment,
File: lines[file.Val.(int64)].Name,
IsVariable: true,
})
@@ -312,7 +322,7 @@ func readMachOSymbolAddresses(path string) (map[string]int, []addressLine, error
if err != nil {
return nil, nil, err
}
- lines, err := readProgramSizeFromDWARF(dwarf, 0, false)
+ lines, err := readProgramSizeFromDWARF(dwarf, 0, 0, false)
if err != nil {
return nil, nil, err
}
@@ -369,10 +379,15 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
// Load the binary file, which could be in a number of file formats.
var sections []memorySection
if file, err := elf.NewFile(f); err == nil {
+ var codeAlignment uint64
+ switch file.Machine {
+ case elf.EM_ARM:
+ codeAlignment = 4 // usually 2, but can be 4
+ }
// Read DWARF information. The error is intentionally ignored.
data, _ := file.DWARF()
if data != nil {
- addresses, err = readProgramSizeFromDWARF(data, 0, true)
+ addresses, err = readProgramSizeFromDWARF(data, 0, codeAlignment, true)
if err != nil {
// However, _do_ report an error here. Something must have gone
// wrong while trying to parse DWARF data.
@@ -430,6 +445,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
sections = append(sections, memorySection{
Address: section.Addr,
Size: section.Size,
+ Align: section.Addralign,
Type: memoryStack,
})
} else {
@@ -437,6 +453,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
sections = append(sections, memorySection{
Address: section.Addr,
Size: section.Size,
+ Align: section.Addralign,
Type: memoryBSS,
})
}
@@ -445,6 +462,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
sections = append(sections, memorySection{
Address: section.Addr,
Size: section.Size,
+ Align: section.Addralign,
Type: memoryCode,
})
} else if section.Type == elf.SHT_PROGBITS && section.Flags&elf.SHF_WRITE != 0 {
@@ -452,6 +470,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
sections = append(sections, memorySection{
Address: section.Addr,
Size: section.Size,
+ Align: section.Addralign,
Type: memoryData,
})
} else if section.Type == elf.SHT_PROGBITS {
@@ -459,6 +478,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
sections = append(sections, memorySection{
Address: section.Addr,
Size: section.Size,
+ Align: section.Addralign,
Type: memoryROData,
})
}
@@ -485,6 +505,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
sections = append(sections, memorySection{
Address: section.Addr,
Size: uint64(section.Size),
+ Align: uint64(section.Align),
Type: memoryCode,
})
} else if sectionType == 1 { // S_ZEROFILL
@@ -492,6 +513,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
sections = append(sections, memorySection{
Address: section.Addr,
Size: uint64(section.Size),
+ Align: uint64(section.Align),
Type: memoryBSS,
})
} else if segment.Maxprot&0b011 == 0b001 { // --r (read-only data)
@@ -499,6 +521,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
sections = append(sections, memorySection{
Address: section.Addr,
Size: uint64(section.Size),
+ Align: uint64(section.Align),
Type: memoryROData,
})
} else {
@@ -506,6 +529,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
sections = append(sections, memorySection{
Address: section.Addr,
Size: uint64(section.Size),
+ Align: uint64(section.Align),
Type: memoryData,
})
}
@@ -589,7 +613,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
// Read DWARF information. The error is intentionally ignored.
data, _ := file.DWARF()
if data != nil {
- addresses, err = readProgramSizeFromDWARF(data, 0, true)
+ addresses, err = readProgramSizeFromDWARF(data, 0, 0, true)
if err != nil {
// However, _do_ report an error here. Something must have gone
// wrong while trying to parse DWARF data.
@@ -661,7 +685,7 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
// Read DWARF information. The error is intentionally ignored.
data, _ := file.DWARF()
if data != nil {
- addresses, err = readProgramSizeFromDWARF(data, codeOffset, true)
+ addresses, err = readProgramSizeFromDWARF(data, codeOffset, 0, true)
if err != nil {
// However, _do_ report an error here. Something must have gone
// wrong while trying to parse DWARF data.
@@ -821,10 +845,18 @@ func readSection(section memorySection, addresses []addressLine, addSize func(st
if addr < line.Address {
// There is a gap: there is a space between the current and the
// previous line entry.
- addSize("(unknown)", line.Address-addr, false)
- if sizesDebug {
- fmt.Printf("%08x..%08x %5d: unknown (gap)\n", addr, line.Address, line.Address-addr)
+ // Check whether this is caused by alignment requirements.
+ addrAligned := (addr + line.Align - 1) &^ (line.Align - 1)
+ if line.Align > 1 && addrAligned >= line.Address {
+ // It is, assume that's what causes the gap.
+ addSize("(padding)", line.Address-addr, true)
+ } else {
+ addSize("(unknown)", line.Address-addr, false)
+ if sizesDebug {
+ fmt.Printf("%08x..%08x %5d: unknown (gap), alignment=%d\n", addr, line.Address, line.Address-addr, line.Align)
+ }
}
+ addr = line.Address
}
if addr > line.Address+line.Length {
// The current line is already covered by a previous line entry.
@@ -846,9 +878,16 @@ func readSection(section memorySection, addresses []addressLine, addSize func(st
}
if addr < sectionEnd {
// There is a gap at the end of the section.
- addSize("(unknown)", sectionEnd-addr, false)
- if sizesDebug {
- fmt.Printf("%08x..%08x %5d: unknown (end)\n", addr, sectionEnd, sectionEnd-addr)
+ addrAligned := (addr + section.Align - 1) &^ (section.Align - 1)
+ if section.Align > 1 && addrAligned >= sectionEnd {
+ // The gap is caused by the section alignment.
+ // For example, if a .rodata section ends with a non-aligned string.
+ addSize("(padding)", sectionEnd-addr, true)
+ } else {
+ addSize("(unknown)", sectionEnd-addr, false)
+ if sizesDebug {
+ fmt.Printf("%08x..%08x %5d: unknown (end), alignment=%d\n", addr, sectionEnd, sectionEnd-addr, section.Align)
+ }
}
}
}