Estou usando C++ para um projeto de firmware de baixo nível para um microcontrolador. Tudo estava bem por um tempo, com o tamanho do código mantido muito pequeno, até que introduzi esta linha de código:
uint8_t index = __builtin_ctz(exti_set_mask);
auto &gpio_irq_info = irq_callback_table[index];
O problema aqui é que irq_callback_table
é um std::array<>
de tamanho 16. exti_set_mask
É um uint16_t
que provavelmente está sendo promovido para uma uint32_t
(arquitetura de CPU de 32 bits), então o compilador não pode ter certeza de que o resultado de __builtin_ctz()
retorna algo menor que 16. Com o potencial de um acesso fora dos limites, o tamanho do código do programa explode por causa de todo o código adicionado para dar suporte ao lançamento de uma exceção.
Mascarar o resultado antes de usá-lo como índice elimina todo esse código de exceção:
uint8_t index = __builtin_ctz(exti_set_mask) & 0xf;
auto &gpio_irq_info = irq_callback_table[index];
O que reduz o tamanho do código do programa para cerca de 4 kB contra 90 kB!
Tenho essas bandeiras definidas via meson
:
# Specify global compiler flags.
add_project_arguments(
# Free standing environment (no OS, or stdlib)
'-ffreestanding', '-nostdlib', '-specs=nosys.specs',
# Enable linker garbage collection
'-ffunction-sections', '-fdata-sections',
# No dynamic memory allocation
'-fno-builtin-malloc', '-fno-builtin-calloc',
'-fno-builtin-realloc', '-fno-builtin-free',
# Debug optimization
'-Og',
language: ['cpp', 'c']
)
add_project_arguments(
'-std=c++20',
'-fno-exceptions',
'-fno-rtti',
language: ['cpp']
)
Mas o -fno-exceptions
sinalizador não parece ser suficiente para evitar a emissão de código de exceção. Idealmente, eu gostaria que qualquer emissão potencial de exceções (ou malloc, etc.) aparecesse como um aviso ou erro. Alguma ideia de como fazer isso?
EDIT: Para aqueles que desejam comparar a saída do arquivo .elf objdump, aqui está o .elf totalmente vinculado com o índice mascarado: https://pastebin.com/hSJgF3PW
E o .elf com o índice não mascarado:
- https://pastebin.com/p9yDxdjx pt1
- https://pastebin.com/NU5nV0tr pt2
- https://pastebin.com/9CX1EtH0 pt3
- https://pastebin.com/evvnmCCa pt4
A função onde os dois se desviam:
Índice não mascarado:
08000d1c <(anonymous namespace)::CommonISRHandler(unsigned short)>:
void CommonISRHandler([[maybe_unused]] uint16_t exti_set_mask) {
8000d1c: b570 push {r4, r5, r6, lr}
8000d1e: 0005 movs r5, r0
while (exti_set_mask) {
8000d20: e011 b.n 8000d46 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x2a>
// Element access.
[[__nodiscard__]]
_GLIBCXX17_CONSTEXPR reference
operator[](size_type __n) noexcept
{
__glibcxx_requires_subscript(__n);
8000d22: 4b18 ldr r3, [pc, #96] @ (8000d84 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x68>)
8000d24: 4a18 ldr r2, [pc, #96] @ (8000d88 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x6c>)
8000d26: 4819 ldr r0, [pc, #100] @ (8000d8c <(anonymous namespace)::CommonISRHandler(unsigned short)+0x70>)
8000d28: 21ca movs r1, #202 @ 0xca
8000d2a: f000 f97d bl 8001028 <std::__glibcxx_assert_fail(char const*, int, char const*, char const*)>
EXTI->RPR1 &= (1 << index);
8000d2e: 4a18 ldr r2, [pc, #96] @ (8000d90 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x74>)
8000d30: 68d1 ldr r1, [r2, #12]
8000d32: 2301 movs r3, #1
8000d34: 40a3 lsls r3, r4
8000d36: 4019 ands r1, r3
8000d38: 60d1 str r1, [r2, #12]
EXTI->FPR1 &= (1 << index);
8000d3a: 6911 ldr r1, [r2, #16]
8000d3c: 4019 ands r1, r3
8000d3e: 6111 str r1, [r2, #16]
exti_set_mask &= ~(1 << index);
8000d40: 43db mvns r3, r3
8000d42: b21b sxth r3, r3
8000d44: 401d ands r5, r3
while (exti_set_mask) {
8000d46: 2d00 cmp r5, #0
8000d48: d01a beq.n 8000d80 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x64>
uint8_t index = __builtin_ctz(exti_set_mask);
8000d4a: 0028 movs r0, r5
8000d4c: f7ff fa40 bl 80001d0 <__ctzsi2>
auto &gpio_irq_info = irq_callback_table[index];
8000d50: 24ff movs r4, #255 @ 0xff
8000d52: 4004 ands r4, r0
8000d54: 2c0f cmp r4, #15
8000d56: d8e4 bhi.n 8000d22 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x6>
return stub_ptr != nullptr;
8000d58: 4b0e ldr r3, [pc, #56] @ (8000d94 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x78>)
8000d5a: 0062 lsls r2, r4, #1
8000d5c: 1912 adds r2, r2, r4
8000d5e: 0092 lsls r2, r2, #2
8000d60: 189b adds r3, r3, r2
8000d62: 689b ldr r3, [r3, #8]
if (gpio_irq_info.callback.IsValid()) {
8000d64: 2b00 cmp r3, #0
8000d66: d0e2 beq.n 8000d2e <(anonymous namespace)::CommonISRHandler(unsigned short)+0x12>
gpio_irq_info.callback(gpio_irq_info.pin);
8000d68: 4a0a ldr r2, [pc, #40] @ (8000d94 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x78>)
8000d6a: 0060 lsls r0, r4, #1
8000d6c: 1901 adds r1, r0, r4
8000d6e: 0089 lsls r1, r1, #2
8000d70: 5c89 ldrb r1, [r1, r2]
8000d72: 1900 adds r0, r0, r4
8000d74: 0080 lsls r0, r0, #2
8000d76: 1880 adds r0, r0, r2
8000d78: 3004 adds r0, #4
8000d7a: f7ff ffbb bl 8000cf4 <rtlib::Delegate<void (mcu::stm32g070::Gpio::GpioId)>::operator()(mcu::stm32g070::Gpio::GpioId) const>
8000d7e: e7d6 b.n 8000d2e <(anonymous namespace)::CommonISRHandler(unsigned short)+0x12>
}
8000d80: bd70 pop {r4, r5, r6, pc}
8000d82: 46c0 nop @ (mov r8, r8)
8000d84: 08013ccc .word 0x08013ccc
8000d88: 08013ce0 .word 0x08013ce0
8000d8c: 08013dc4 .word 0x08013dc4
8000d90: 40021800 .word 0x40021800
8000d94: 20000734 .word 0x20000734
Índice mascarado:
08000710 <(anonymous namespace)::CommonISRHandler(unsigned short)>:
void CommonISRHandler([[maybe_unused]] uint16_t exti_set_mask) {
8000710: b570 push {r4, r5, r6, lr}
8000712: 0005 movs r5, r0
while (exti_set_mask) {
8000714: e00b b.n 800072e <(anonymous namespace)::CommonISRHandler(unsigned short)+0x1e>
EXTI->RPR1 &= (1 << index);
8000716: 4a14 ldr r2, [pc, #80] @ (8000768 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x58>)
8000718: 68d1 ldr r1, [r2, #12]
800071a: 2301 movs r3, #1
800071c: 40a3 lsls r3, r4
800071e: 4019 ands r1, r3
8000720: 60d1 str r1, [r2, #12]
EXTI->FPR1 &= (1 << index);
8000722: 6911 ldr r1, [r2, #16]
8000724: 4019 ands r1, r3
8000726: 6111 str r1, [r2, #16]
exti_set_mask &= ~(1 << index);
8000728: 43db mvns r3, r3
800072a: b21b sxth r3, r3
800072c: 401d ands r5, r3
while (exti_set_mask) {
800072e: 2d00 cmp r5, #0
8000730: d018 beq.n 8000764 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x54>
uint8_t index = __builtin_ctz(exti_set_mask) & 0xf;
8000732: 0028 movs r0, r5
8000734: f7ff fcc0 bl 80000b8 <__ctzsi2>
8000738: 240f movs r4, #15
800073a: 4004 ands r4, r0
return stub_ptr != nullptr;
800073c: 4b0b ldr r3, [pc, #44] @ (800076c <(anonymous namespace)::CommonISRHandler(unsigned short)+0x5c>)
800073e: 0062 lsls r2, r4, #1
8000740: 1912 adds r2, r2, r4
8000742: 0092 lsls r2, r2, #2
8000744: 189b adds r3, r3, r2
8000746: 689b ldr r3, [r3, #8]
if (gpio_irq_info.callback.IsValid()) {
8000748: 2b00 cmp r3, #0
800074a: d0e4 beq.n 8000716 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x6>
gpio_irq_info.callback(gpio_irq_info.pin);
800074c: 4a07 ldr r2, [pc, #28] @ (800076c <(anonymous namespace)::CommonISRHandler(unsigned short)+0x5c>)
800074e: 0060 lsls r0, r4, #1
8000750: 1901 adds r1, r0, r4
8000752: 0089 lsls r1, r1, #2
8000754: 5c89 ldrb r1, [r1, r2]
8000756: 1900 adds r0, r0, r4
8000758: 0080 lsls r0, r0, #2
800075a: 1880 adds r0, r0, r2
800075c: 3004 adds r0, #4
800075e: f7ff ffc3 bl 80006e8 <rtlib::Delegate<void (mcu::stm32g070::Gpio::GpioId)>::operator()(mcu::stm32g070::Gpio::GpioId) const>
8000762: e7d8 b.n 8000716 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x6>
}
8000764: bd70 pop {r4, r5, r6, pc}
8000766: 46c0 nop @ (mov r8, r8)
8000768: 40021800 .word 0x40021800
800076c: 2000005c .word 0x2000005c
EDIT #2 , Alguns bons comentários até agora, obrigado. Minha razão para acreditar que exceções estão sendo puxadas é por causa da presença de muitas funções no objdump não mascarado que não estão presentes na saída do objdump mascarado ( grep -i exception
, grep -i throw
):
08000438 <_Unwind_RaiseException>:
800045e: f009 f831 bl 80094c4 <__gnu_Unwind_RaiseException>
8001764: f007 fb0e bl 8008d84 <__cxa_current_exception_type>
080089d8 <__cxxabiv1::__is_gxx_exception_class(char*)>:
80089e0: d000 beq.n 80089e4 <__cxxabiv1::__is_gxx_exception_class(char*)+0xc>
80089e8: d1fb bne.n 80089e2 <__cxxabiv1::__is_gxx_exception_class(char*)+0xa>
80089ee: d1f8 bne.n 80089e2 <__cxxabiv1::__is_gxx_exception_class(char*)+0xa>
80089f4: d1f5 bne.n 80089e2 <__cxxabiv1::__is_gxx_exception_class(char*)+0xa>
80089fa: d1f2 bne.n 80089e2 <__cxxabiv1::__is_gxx_exception_class(char*)+0xa>
8008a00: d1ef bne.n 80089e2 <__cxxabiv1::__is_gxx_exception_class(char*)+0xa>
8008a06: d1ec bne.n 80089e2 <__cxxabiv1::__is_gxx_exception_class(char*)+0xa>
8008a12: e7e6 b.n 80089e2 <__cxxabiv1::__is_gxx_exception_class(char*)+0xa>
8008a20: f7ff ffda bl 80089d8 <__cxxabiv1::__is_gxx_exception_class(char*)>
8008a44: f7ff ffc8 bl 80089d8 <__cxxabiv1::__is_gxx_exception_class(char*)>
8008b02: f000 fad3 bl 80090ac <__cxa_allocate_exception>
8008bc0: f000 fce6 bl 8009590 <_Unwind_DeleteException>
8008c2c: f000 fcb0 bl 8009590 <_Unwind_DeleteException>
08008c34 <std::bad_exception::~bad_exception()>:
08008c38 <transaction clone for std::bad_exception::what() const>:
8008c38: 4800 ldr r0, [pc, #0] @ (8008c3c <transaction clone for std::bad_exception::what() const+0x4>)
08008c40 <std::bad_exception::~bad_exception()>:
08008c60 <__gxx_exception_cleanup(_Unwind_Reason_Code, _Unwind_Control_Block*)>:
8008c64: d812 bhi.n 8008c8c <__gxx_exception_cleanup(_Unwind_Reason_Code, _Unwind_Control_Block*)+0x2c>
8008c72: d000 beq.n 8008c76 <__gxx_exception_cleanup(_Unwind_Reason_Code, _Unwind_Control_Block*)+0x16>
8008c7e: d001 beq.n 8008c84 <__gxx_exception_cleanup(_Unwind_Reason_Code, _Unwind_Control_Block*)+0x24>
8008c86: f000 fa27 bl 80090d8 <__cxa_free_exception>
8008c8a: e7f3 b.n 8008c74 <__gxx_exception_cleanup(_Unwind_Reason_Code, _Unwind_Control_Block*)+0x14>
08008c94 <__cxa_init_primary_exception>:
8008cd0: 4b02 ldr r3, [pc, #8] @ (8008cdc <__cxa_init_primary_exception+0x48>)
8008cf8: f7ff ffcc bl 8008c94 <__cxa_init_primary_exception>
8008d06: f7f7 fb97 bl 8000438 <_Unwind_RaiseException>
08008d84 <__cxa_current_exception_type>:
8008d8e: d004 beq.n 8008d9a <__cxa_current_exception_type+0x16>
8008d96: d001 beq.n 8008d9c <__cxa_current_exception_type+0x18>
8008da0: e7fa b.n 8008d98 <__cxa_current_exception_type+0x14>
080090ac <__cxa_allocate_exception>:
80090b8: d007 beq.n 80090ca <__cxa_allocate_exception+0x1e>
80090d2: d1f2 bne.n 80090ba <__cxa_allocate_exception+0xe>
080090d8 <__cxa_free_exception>:
80090d8: 4b07 ldr r3, [pc, #28] @ (80090f8 <__cxa_free_exception+0x20>)
80090e6: d201 bcs.n 80090ec <__cxa_free_exception+0x14>
80090ea: d302 bcc.n 80090f2 <__cxa_free_exception+0x1a>
80090f6: e7fb b.n 80090f0 <__cxa_free_exception+0x18>
080094c4 <__gnu_Unwind_RaiseException>:
80094e0: e006 b.n 80094f0 <__gnu_Unwind_RaiseException+0x2c>
80094ee: d108 bne.n 8009502 <__gnu_Unwind_RaiseException+0x3e>
80094fa: d0f2 beq.n 80094e2 <__gnu_Unwind_RaiseException+0x1e>
800950a: d1f7 bne.n 80094fc <__gnu_Unwind_RaiseException+0x38>
8009584: f7ff ff9e bl 80094c4 <__gnu_Unwind_RaiseException>
08009590 <_Unwind_DeleteException>:
8009598: d001 beq.n 800959e <_Unwind_DeleteException+0xe>
08000498 <_Unwind_Resume_or_Rethrow>:
80004be: f009 f857 bl 8009570 <__gnu_Unwind_Resume_or_Rethrow>
80017c6: f007 faa5 bl 8008d14 <__cxa_rethrow>
8008ad0: f000 f920 bl 8008d14 <__cxa_rethrow>
8008b0e: f000 f8e7 bl 8008ce0 <__cxa_throw>
08008ce0 <__cxa_throw>:
08008d14 <__cxa_rethrow>:
8008d24: d00c beq.n 8008d40 <__cxa_rethrow+0x2c>
8008d2c: d00a beq.n 8008d44 <__cxa_rethrow+0x30>
8008d36: f7f7 fbaf bl 8000498 <_Unwind_Resume_or_Rethrow>
8008d4a: d1f0 bne.n 8008d2e <__cxa_rethrow+0x1a>
8008d52: d1ec bne.n 8008d2e <__cxa_rethrow+0x1a>
8008d5a: d1e8 bne.n 8008d2e <__cxa_rethrow+0x1a>
8008d62: d1e4 bne.n 8008d2e <__cxa_rethrow+0x1a>
8008d6a: d1e0 bne.n 8008d2e <__cxa_rethrow+0x1a>
8008d72: d1dc bne.n 8008d2e <__cxa_rethrow+0x1a>
8008d7a: d8d8 bhi.n 8008d2e <__cxa_rethrow+0x1a>
8008d82: e7d6 b.n 8008d32 <__cxa_rethrow+0x1e>
08009570 <__gnu_Unwind_Resume_or_Rethrow>:
8009576: d005 beq.n 8009584 <__gnu_Unwind_Resume_or_Rethrow+0x14>
8009588: e7fb b.n 8009582 <__gnu_Unwind_Resume_or_Rethrow+0x12>