mirror of
https://github.com/esphome/esphome.git
synced 2026-09-02 02:56:01 +00:00
libretiny: print IRAM_ATTR placement summary after link
After linking, walk the ELF symbol table and print one of:
ESPHome: IRAM_ATTR placement summary (BK7231N):
.sram.text: 312 bytes at 0x004001d0 - 0x00400308
ESPHome: IRAM_ATTR placement summary (RTL8720C):
IRAM symbols at 0x10002f6c - 0x10002fa8 (approx 60 bytes)
On the three families whose linker scripts we already patch (BK72xx, LN882H,
RTL8710B) the PROVIDE(__esphome_sram_text_start/end = .) markers injected
alongside KEEP(*(.sram.text*)) give an exact byte count for the ESPHome
IRAM_ATTR contribution. On RTL8720C we cannot patch the linker script (it
is loaded directly from the framework package) so the summary falls back to
reading the addresses of the three core IRAM_ATTR symbols. Either way the
address range is visible proof that the functions ended up in SRAM rather
than flash.
This commit is contained in:
@@ -20,11 +20,19 @@ import re
|
||||
|
||||
|
||||
_MARKER = "/* esphome .sram.text */"
|
||||
_KEEP_LINE = " KEEP(*(.sram.text*)) " + _MARKER + "\n"
|
||||
_KEEP_LINE = (
|
||||
" PROVIDE(__esphome_sram_text_start = .); "
|
||||
"KEEP(*(.sram.text*)) "
|
||||
"PROVIDE(__esphome_sram_text_end = .); "
|
||||
+ _MARKER + "\n"
|
||||
)
|
||||
_BK_DATA = re.compile(r"(\.data\s*:\s*\{\s*\n)")
|
||||
_BK_RW_NO_X = re.compile(r"(\bram\s*\()\s*rw\s*!\s*x(\s*\))")
|
||||
_LN_COPY = re.compile(r"(\.flash_copysection\s*:\s*\{\s*\n)")
|
||||
_RTL8710B_IMAGE2 = re.compile(r"(\.image2\.ram\.text\s*:\s*\{\s*\n)")
|
||||
# RTL8720C loads its linker script directly from the framework package so we
|
||||
# cannot inject PROVIDE markers for it; the summary falls back to reading
|
||||
# addresses of known IRAM_ATTR symbols instead of measuring a bracketed span.
|
||||
|
||||
|
||||
def _detect(env):
|
||||
@@ -82,6 +90,8 @@ def _patchers_for(variant):
|
||||
return (_patch_ln882h,)
|
||||
if variant == "RTL8710B":
|
||||
return (_patch_rtl8710b,)
|
||||
# RTL8720C: stock linker already consumes *(.sram.text*), no .ld patch
|
||||
# needed; summary falls back to reading symbol addresses.
|
||||
return ()
|
||||
|
||||
|
||||
@@ -118,6 +128,49 @@ def _pre_link(target, source, env):
|
||||
_patch_build_dir(_patchers, env.subst("$BUILD_DIR"))
|
||||
|
||||
|
||||
def _post_link(target, source, env):
|
||||
"""Print where IRAM_ATTR ended up so users can confirm at a glance."""
|
||||
nm = env.subst("$NM") or "arm-none-eabi-nm"
|
||||
elf = env.subst("$BUILD_DIR/${PROGNAME}.elf")
|
||||
if not os.path.isfile(elf):
|
||||
return
|
||||
try:
|
||||
import subprocess
|
||||
out = subprocess.check_output([nm, "--defined-only", elf], text=True)
|
||||
except (OSError, subprocess.CalledProcessError):
|
||||
return
|
||||
start = end = None
|
||||
sample = []
|
||||
for line in out.splitlines():
|
||||
parts = line.split(maxsplit=2)
|
||||
if len(parts) != 3:
|
||||
continue
|
||||
addr, _kind, name = parts
|
||||
if name == "__esphome_sram_text_start":
|
||||
start = int(addr, 16)
|
||||
elif name == "__esphome_sram_text_end":
|
||||
end = int(addr, 16)
|
||||
elif name in (
|
||||
"_ZN7esphome21wake_loop_any_contextEv",
|
||||
"_ZN7esphome17wake_loop_isrsafeEPl",
|
||||
"_ZN7esphome9Component28enable_loop_soon_any_contextEv",
|
||||
):
|
||||
sample.append((int(addr, 16), name))
|
||||
header = "ESPHome: IRAM_ATTR placement summary ({}):".format(_variant)
|
||||
if start is not None and end is not None:
|
||||
print(header)
|
||||
print(" .sram.text: {} bytes at 0x{:08x} - 0x{:08x}".format(end - start, start, end))
|
||||
elif sample:
|
||||
print(header)
|
||||
sample.sort()
|
||||
lo = sample[0][0]
|
||||
hi = sample[-1][0]
|
||||
print(" IRAM symbols at 0x{:08x} - 0x{:08x} (approx {} bytes)".format(lo, hi, hi - lo))
|
||||
else:
|
||||
print(header)
|
||||
print(" no IRAM_ATTR symbols found in the ELF")
|
||||
|
||||
|
||||
_variant = _detect(env)
|
||||
|
||||
if _variant is None:
|
||||
@@ -139,3 +192,6 @@ if _patchers:
|
||||
# own builder setup, which may run after this script. Register the patch
|
||||
# as a pre-link action so it executes once the linker scripts exist.
|
||||
env.AddPreAction("$BUILD_DIR/${PROGNAME}.elf", _pre_link)
|
||||
|
||||
# Post-link summary runs for every LibreTiny family.
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.elf", _post_link)
|
||||
|
||||
Reference in New Issue
Block a user