Browse Source

darwin: support -size= flag

This is just basic support. It doesn't add support for reading DWARF,
because that's a bit complicated on MacOS (it isn't stored in the file
itself but separately in the object files). But at least this change
makes it possible to easily print executable sizes by section type like
for other operating systems.
pull/2868/head
Ayke van Laethem 2 years ago
committed by Ron Evans
parent
commit
c23a5b65ef
  1. 4
      Makefile
  2. 53
      builder/sizes.go

4
Makefile

@ -634,8 +634,8 @@ endif
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
GOOS=linux GOARCH=arm $(TINYGO) build -size short -o test.elf ./testdata/cgo GOOS=linux GOARCH=arm $(TINYGO) build -size short -o test.elf ./testdata/cgo
GOOS=windows GOARCH=amd64 $(TINYGO) build -size short -o test.exe ./testdata/cgo GOOS=windows GOARCH=amd64 $(TINYGO) build -size short -o test.exe ./testdata/cgo
GOOS=darwin GOARCH=amd64 $(TINYGO) build -o test ./testdata/cgo GOOS=darwin GOARCH=amd64 $(TINYGO) build -size short -o test ./testdata/cgo
GOOS=darwin GOARCH=arm64 $(TINYGO) build -o test ./testdata/cgo GOOS=darwin GOARCH=arm64 $(TINYGO) build -size short -o test ./testdata/cgo
ifneq ($(OS),Windows_NT) ifneq ($(OS),Windows_NT)
# TODO: this does not yet work on Windows. Somehow, unused functions are # TODO: this does not yet work on Windows. Somehow, unused functions are
# not garbage collected. # not garbage collected.

53
builder/sizes.go

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"debug/dwarf" "debug/dwarf"
"debug/elf" "debug/elf"
"debug/macho"
"debug/pe" "debug/pe"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
@ -368,6 +369,58 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
}) })
} }
} }
} else if file, err := macho.NewFile(f); err == nil {
// TODO: read DWARF information. On MacOS, DWARF debug information isn't
// stored in the executable but stays in the object files. The
// executable does however contain the object file paths that contain
// debug information.
// Read segments, for use while reading through sections.
segments := map[string]*macho.Segment{}
for _, load := range file.Loads {
switch load := load.(type) {
case *macho.Segment:
segments[load.Name] = load
}
}
// Read MachO sections.
for _, section := range file.Sections {
sectionType := section.Flags & 0xff
sectionFlags := section.Flags >> 8
segment := segments[section.Seg]
// For the constants used here, see:
// https://github.com/llvm/llvm-project/blob/release/14.x/llvm/include/llvm/BinaryFormat/MachO.h
if sectionFlags&0x800000 != 0 { // S_ATTR_PURE_INSTRUCTIONS
// Section containing only instructions.
sections = append(sections, memorySection{
Address: section.Addr,
Size: uint64(section.Size),
Type: memoryCode,
})
} else if sectionType == 1 { // S_ZEROFILL
// Section filled with zeroes on demand.
sections = append(sections, memorySection{
Address: section.Addr,
Size: uint64(section.Size),
Type: memoryBSS,
})
} else if segment.Maxprot&0b011 == 0b001 { // --r (read-only data)
// Protection doesn't allow writes, so mark this section read-only.
sections = append(sections, memorySection{
Address: section.Addr,
Size: uint64(section.Size),
Type: memoryROData,
})
} else {
// The rest is assumed to be regular data.
sections = append(sections, memorySection{
Address: section.Addr,
Size: uint64(section.Size),
Type: memoryData,
})
}
}
} else if file, err := pe.NewFile(f); err == nil { } else if file, err := pe.NewFile(f); err == nil {
// Read DWARF information. The error is intentionally ignored. // Read DWARF information. The error is intentionally ignored.
data, _ := file.DWARF() data, _ := file.DWARF()

Loading…
Cancel
Save