Skip to content

Commit 850a2f6

Browse files
authored
Merge pull request #385 from gibix/extra/check-size
tools: replace arm-zephyr-eabi-size with zephyr-check-size
2 parents 18d20e6 + 40db761 commit 850a2f6

3 files changed

Lines changed: 111 additions & 0 deletions

File tree

tools/zephyr-check-size/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
zephyr-check-size

tools/zephyr-check-size/go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/arduino/zephyr-check-size
2+
3+
go 1.25.5

tools/zephyr-check-size/main.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// Copyright (c) Arduino s.r.l. and/or its affiliated companies
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package main
5+
6+
import (
7+
"bufio"
8+
"debug/elf"
9+
"fmt"
10+
"os"
11+
"strings"
12+
)
13+
14+
func main() {
15+
if len(os.Args) != 5 {
16+
fmt.Fprintf(os.Stderr, "Usage: %s <link_mode> <config_path> <upload_file> <elf_file>\n\n", os.Args[0])
17+
fmt.Fprintf(os.Stderr, "Computes sketch size for Arduino IDE.\n\n")
18+
fmt.Fprintf(os.Stderr, "Arguments:\n")
19+
fmt.Fprintf(os.Stderr, " link_mode 'static' or 'dynamic'\n")
20+
fmt.Fprintf(os.Stderr, " config_path Path to Zephyr .config file\n")
21+
fmt.Fprintf(os.Stderr, " upload_file Path to upload binary (for flash size)\n")
22+
fmt.Fprintf(os.Stderr, " elf_file Path to ELF file (for section analysis)\n")
23+
os.Exit(1)
24+
}
25+
26+
linkMode := os.Args[1]
27+
configPath := os.Args[2]
28+
uploadFile := os.Args[3]
29+
elfFile := os.Args[4]
30+
31+
// Flash size = filesystem size of the upload file
32+
flashSize, err := fileSize(uploadFile)
33+
if err != nil {
34+
fmt.Fprintf(os.Stderr, "Error reading upload file: %v\n", err)
35+
os.Exit(1)
36+
}
37+
38+
// Heap size = sum of relevant ELF sections
39+
heapSize, err := computeHeapSize(elfFile, linkMode, configPath)
40+
if err != nil {
41+
fmt.Fprintf(os.Stderr, "Error computing heap size: %v\n", err)
42+
os.Exit(1)
43+
}
44+
45+
fmt.Printf(".text %12d\n", flashSize)
46+
fmt.Printf(".data %12d\n", heapSize)
47+
}
48+
49+
func fileSize(path string) (int64, error) {
50+
info, err := os.Stat(path)
51+
if err != nil {
52+
return 0, err
53+
}
54+
return info.Size(), nil
55+
}
56+
57+
func computeHeapSize(elfFile, linkMode, configPath string) (uint64, error) {
58+
f, err := elf.Open(elfFile)
59+
if err != nil {
60+
return 0, err
61+
}
62+
defer f.Close()
63+
64+
noReloc := false
65+
if linkMode == "dynamic" {
66+
noReloc = checkConfigFlag(configPath, "CONFIG_LLEXT_RODATA_NO_RELOC")
67+
}
68+
69+
var total uint64
70+
for _, section := range f.Sections {
71+
if section.Flags&elf.SHF_ALLOC == 0 {
72+
continue
73+
}
74+
75+
if linkMode == "static" {
76+
// // Static mode: only writable sections (.data, .bss) use RAM
77+
if section.Flags&elf.SHF_WRITE != 0 {
78+
total += section.Size
79+
}
80+
} else {
81+
// Dynamic mode: all allocated sections go to LLEXT heap.
82+
if noReloc && strings.HasPrefix(section.Name, ".llext.rodata.noreloc") {
83+
continue
84+
}
85+
total += section.Size
86+
}
87+
}
88+
89+
return total, nil
90+
}
91+
92+
func checkConfigFlag(configPath, key string) bool {
93+
f, err := os.Open(configPath)
94+
if err != nil {
95+
return false
96+
}
97+
defer f.Close()
98+
99+
target := key + "=y"
100+
scanner := bufio.NewScanner(f)
101+
for scanner.Scan() {
102+
if strings.TrimSpace(scanner.Text()) == target {
103+
return true
104+
}
105+
}
106+
return false
107+
}

0 commit comments

Comments
 (0)