Fix lives in: protobuf
What the workaround does
We empty-redefine the Abseil section attribute macro on every protobuf-related target so the custom section attribute disappears and descriptor tables fall back to default placement (.rodata):
# cmake/protobuf_setup.cmake:160-169
foreach(target ${vendored_targets})
target_compile_definitions(${target} PRIVATE
ABSL_ATTRIBUTE_SECTION_VARIABLE\(name\)=)
endforeach()
Root cause
protobuf v34's generated .pb.cc files mark descriptor tables with:
PROTOBUF_SECTION_VARIABLE(protodesc_cold)
// expands to: __attribute__((section("protodesc_cold")))
ESP-IDF's sections.ld linker script does not have a mapping for the protodesc_cold section. The unknown section breaks the .flash.appdesc / .flash.rodata contiguous-layout assertion at link time. Bare-metal / firmware platforms generally control their linker scripts tightly and don't expect libraries to invent new output sections.
Glibc / Linux tolerates this because the linker creates a default output section for any unknown input section; bare-metal linker scripts that use KEEP(*(.foo)) enumeration explicitly do not.
Proposed fix
Two options in protobuf:
-
Default to .rodata for descriptor tables. Gate the protodesc_cold attribute behind an explicit opt-in CMake option (PROTOBUF_USE_COLD_SECTION=ON). This is the cleanest fix — the section is a size-optimization for cold descriptors, not a correctness requirement.
-
Guard the attribute with __has_attribute(section) plus a portability check for bare-metal targets — but this would still need a way for the consumer to disable it, since the attribute compiles fine, the linker is the one that complains.
Approach 1 is preferable because it makes the default behavior portable and the optimization explicit.
What we delete once fixed
- The
ABSL_ATTRIBUTE_SECTION_VARIABLE(name)= empty redefine in cmake/protobuf_setup.cmake:160-169
Fix lives in: protobuf
What the workaround does
We empty-redefine the Abseil section attribute macro on every protobuf-related target so the custom section attribute disappears and descriptor tables fall back to default placement (
.rodata):Root cause
protobuf v34's generated
.pb.ccfiles mark descriptor tables with:ESP-IDF's
sections.ldlinker script does not have a mapping for theprotodesc_coldsection. The unknown section breaks the.flash.appdesc/.flash.rodatacontiguous-layout assertion at link time. Bare-metal / firmware platforms generally control their linker scripts tightly and don't expect libraries to invent new output sections.Glibc / Linux tolerates this because the linker creates a default output section for any unknown input section; bare-metal linker scripts that use
KEEP(*(.foo))enumeration explicitly do not.Proposed fix
Two options in protobuf:
Default to
.rodatafor descriptor tables. Gate theprotodesc_coldattribute behind an explicit opt-in CMake option (PROTOBUF_USE_COLD_SECTION=ON). This is the cleanest fix — the section is a size-optimization for cold descriptors, not a correctness requirement.Guard the attribute with
__has_attribute(section)plus a portability check for bare-metal targets — but this would still need a way for the consumer to disable it, since the attribute compiles fine, the linker is the one that complains.Approach 1 is preferable because it makes the default behavior portable and the optimization explicit.
What we delete once fixed
ABSL_ATTRIBUTE_SECTION_VARIABLE(name)=empty redefine incmake/protobuf_setup.cmake:160-169