Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build(core): export Rust functions' stack sizes #4555

Merged
merged 1 commit into from
Jan 31, 2025
Merged

Conversation

romanz
Copy link
Contributor

@romanz romanz commented Jan 29, 2025

It is useful to find the top-most stack consuming functions:

$ make build_firmware
$ arm-none-eabi-size -A build/firmware/firmware.elf | grep .stack_sizes
.stack_sizes          7523           0

$ cargo install [email protected]
$ stack-sizes build/firmware/firmware.elf | grep trezor_lib | sort -k2 -n | tail -n10
0x081c1721	3536	trezor_lib::ui::api::firmware_micropython::new_confirm_properties::h2ab0feebaf154486
0x081c0e7d	3560	trezor_lib::ui::api::firmware_micropython::new_confirm_modify_output::h04465b97d57fafb6
0x081c6161	3688	trezor_lib::ui::api::firmware_micropython::new_show_checklist::he16b109bc4dff398
0x081c4089	4240	trezor_lib::ui::api::firmware_micropython::new_request_pin::h3280c5eff8900a22
0x081be3e1	4960	trezor_lib::ui::api::firmware_micropython::new_confirm_action::h860f874d714ace74
0x081bf545	5096	trezor_lib::ui::api::firmware_micropython::new_confirm_emphasized::h9ade56f5c88001c0
0x081c1ded	5736	trezor_lib::ui::api::firmware_micropython::new_confirm_summary::he2e1274bbc07703e
0x081c7ee9	6760	trezor_lib::ui::api::firmware_micropython::new_show_remaining_shares::h1f67cbfdfeb4c683
0x081c127d	6768	trezor_lib::ui::api::firmware_micropython::new_confirm_more::h107a4be9b5431bb4
0x081c5441	8312	trezor_lib::ui::api::firmware_micropython::new_show_address_details::h352e0b87c58914ce

[no changelog]

@romanz romanz added core Trezor Core firmware. Runs on Trezor Model T and T2B1. rust Pull requests that update Rust code labels Jan 29, 2025
@romanz romanz self-assigned this Jan 29, 2025
Copy link

github-actions bot commented Jan 29, 2025

core UI changes device test click test persistence test
T2T1 Model T test(screens) main(screens) test(screens) main(screens) test(screens) main(screens)
T3B1 Safe 3 test(screens) main(screens) test(screens) main(screens) test(screens) main(screens)
T3T1 Safe 5 test(screens) main(screens) test(screens) main(screens) test(screens) main(screens)
All main(screens)

@romanz romanz assigned matejcik and unassigned matejcik Jan 29, 2025
@romanz romanz requested review from matejcik and mmilata January 29, 2025 18:54
@romanz romanz marked this pull request as ready for review January 29, 2025 18:54
Copy link
Member

@mmilata mmilata left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to make Cargo install the stack-sizes binary as part of dev-dependencies? Unfortunately it doesn't seem to be available in nixpkgs.

core/SConscript.firmware Outdated Show resolved Hide resolved
@romanz
Copy link
Contributor Author

romanz commented Jan 30, 2025

Is it possible to make Cargo install the stack-sizes binary as part of dev-dependencies?

Good question, not sure if it's possible :(
Maybe it would be simpler to implement the parsing using pyelftools? It doesn't require compilation and doesn't have any extra dependencies...
I can try to do it in a separate PR :)

@romanz romanz changed the title build(core): allow exporting Rust functions' stack sizes build(core): export Rust functions' stack sizes Jan 30, 2025
@mmilata
Copy link
Member

mmilata commented Jan 30, 2025

Perhaps it would make sense to add this functionality to https://github.com/trezor/binsize but leave it up to you if you want to do it.

It is useful to find the top-most stack consuming functions:

```
$ make build_firmware
$ arm-none-eabi-size -A build/firmware/firmware.elf | grep .stack_sizes
.stack_sizes          7523           0

$ cargo install [email protected]
$ stack-sizes build/firmware/firmware.elf | grep trezor_lib | sort -k2 -n | tail -n10
0x081c1721	3536	trezor_lib::ui::api::firmware_micropython::new_confirm_properties::h2ab0feebaf154486
0x081c0e7d	3560	trezor_lib::ui::api::firmware_micropython::new_confirm_modify_output::h04465b97d57fafb6
0x081c6161	3688	trezor_lib::ui::api::firmware_micropython::new_show_checklist::he16b109bc4dff398
0x081c4089	4240	trezor_lib::ui::api::firmware_micropython::new_request_pin::h3280c5eff8900a22
0x081be3e1	4960	trezor_lib::ui::api::firmware_micropython::new_confirm_action::h860f874d714ace74
0x081bf545	5096	trezor_lib::ui::api::firmware_micropython::new_confirm_emphasized::h9ade56f5c88001c0
0x081c1ded	5736	trezor_lib::ui::api::firmware_micropython::new_confirm_summary::he2e1274bbc07703e
0x081c7ee9	6760	trezor_lib::ui::api::firmware_micropython::new_show_remaining_shares::h1f67cbfdfeb4c683
0x081c127d	6768	trezor_lib::ui::api::firmware_micropython::new_confirm_more::h107a4be9b5431bb4
0x081c5441	8312	trezor_lib::ui::api::firmware_micropython::new_show_address_details::h352e0b87c58914ce
```

[no changelog]
@romanz romanz force-pushed the romanz/emit-stack-sizes branch from b508b8a to 5da93c0 Compare January 30, 2025 19:57
@romanz
Copy link
Contributor Author

romanz commented Jan 30, 2025

Perhaps it would make sense to add this functionality to https://github.com/trezor/binsize

Thanks - I'll prepare a pyelftools-based proof-of-concept and consult with @grdddj.

@romanz romanz merged commit 2a19b35 into main Jan 31, 2025
94 checks passed
@romanz romanz deleted the romanz/emit-stack-sizes branch January 31, 2025 05:28
@romanz
Copy link
Contributor Author

romanz commented Feb 6, 2025

FTR, it's possible to parse the Rust stack sizes from firmware.elf using the following Python code:

from elftools.construct import Struct, ULInt32, GreedyRange
from elftools.common.construct_utils import ULEB128
from elftools.elf.elffile import ELFFile

import subprocess
from pathlib import Path

SYMBOL_TYPES = ('t', 'w')  # text, weak

FIRMWARE_ELF = Path('core/build/firmware/firmware.elf')
elf = ELFFile(FIRMWARE_ELF.open('rb'))


def load_address_map():
    out = subprocess.check_output(args=['arm-none-eabi-nm', '--radix=d', '--demangle', FIRMWARE_ELF])
    symbols = (line.decode().split(maxsplit=2) for line in out.splitlines())
    return {
        int(addr): name
        for addr, type, name in symbols
        if type.lower() in SYMBOL_TYPES
    }


def load_stack_sizes():
    stack_sizes = elf.get_section_by_name('.stack_sizes')

    Entries = GreedyRange(Struct("Entry",
        ULInt32("symbol_addr"),
        ULEB128("stack_size"),
    ))
    return Entries.parse(stack_sizes.data())


def main():
    address_map = load_address_map()
    for e in load_stack_sizes():
        symbol_name = address_map[e.symbol_addr]
        print(f'{e.stack_size}\t{symbol_name}')


if __name__ == '__main__':
    main()

Tested on 85bbc89:

$ make build_firmware -C core
<snip>

$ python stack_sizes.py | sort -k1 -n | tail
3520	trezor_lib::ui::api::firmware_micropython::new_confirm_properties
3544	trezor_lib::ui::api::firmware_micropython::new_confirm_modify_output
3704	trezor_lib::ui::api::firmware_micropython::new_show_checklist
4232	trezor_lib::ui::api::firmware_micropython::new_request_pin
4680	trezor_lib::ui::api::firmware_micropython::new_confirm_emphasized
4944	trezor_lib::ui::api::firmware_micropython::new_confirm_action
5736	trezor_lib::ui::api::firmware_micropython::new_confirm_summary
6744	trezor_lib::ui::api::firmware_micropython::new_show_remaining_shares
6760	trezor_lib::ui::api::firmware_micropython::new_confirm_more
8320	trezor_lib::ui::api::firmware_micropython::new_show_address_details

$ ~/.cargo/bin/stack-sizes core/build/firmware/firmware.elf | sort -k2 -n | tail
0x081c154d	3520	trezor_lib::ui::api::firmware_micropython::new_confirm_properties::h2ab0feebaf154486
0x081c0c9d	3544	trezor_lib::ui::api::firmware_micropython::new_confirm_modify_output::h04465b97d57fafb6
0x081c5d31	3704	trezor_lib::ui::api::firmware_micropython::new_show_checklist::he16b109bc4dff398
0x081c3d11	4232	trezor_lib::ui::api::firmware_micropython::new_request_pin::h3280c5eff8900a22
0x081bf405	4680	trezor_lib::ui::api::firmware_micropython::new_confirm_emphasized::h9ade56f5c88001c0
0x081be2ed	4944	trezor_lib::ui::api::firmware_micropython::new_confirm_action::h860f874d714ace74
0x081c1c01	5736	trezor_lib::ui::api::firmware_micropython::new_confirm_summary::he2e1274bbc07703e
0x081c7a0d	6744	trezor_lib::ui::api::firmware_micropython::new_show_remaining_shares::h1f67cbfdfeb4c683
0x081c108d	6760	trezor_lib::ui::api::firmware_micropython::new_confirm_more::h107a4be9b5431bb4
0x081c5095	8320	trezor_lib::ui::api::firmware_micropython::new_show_address_details::h352e0b87c58914ce

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Trezor Core firmware. Runs on Trezor Model T and T2B1. rust Pull requests that update Rust code
Projects
Status: Approved
Development

Successfully merging this pull request may close these issues.

3 participants