mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 19:13:21 +00:00
test(esp_common): Add Linux host test for portable section macros
Add a test app that verifies PLACE_IN_SECTION, _SECTION_ATTR_SYMBOL_DECL_GENERIC, _SECTION_START and _SECTION_END macros work correctly on Linux. The test places 5 uint32_t values into a custom .test_data_table section from two separate translation units, then iterates the section at runtime to verify the correct count and content of all entries. Includes: - Custom linker script (ld/test_section.ld) - Build-test-rules entry (linux only) - pytest host_test marker
This commit is contained in:
@@ -248,13 +248,13 @@ FORCE_INLINE_ATTR TYPE& operator<<=(TYPE& a, int b) { a = a << b; return a; }
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
/* ---------- macOS (Mach-O) ---------- */
|
||||
#include <mach-o/getsect.h>
|
||||
#include <mach-o/ldsyms.h>
|
||||
#include <mach-o/dyld.h>
|
||||
|
||||
#define PLACE_IN_SECTION(SECTION) \
|
||||
#define _SECTION_ATTR_IMPL_GENERIC(SECTION, COUNTER) \
|
||||
__attribute__((used, aligned(4), section("__DATA," SECTION)))
|
||||
|
||||
#define _SECTION_ATTR_IMPL_GENERIC(SECTION, COUNTER) \
|
||||
__attribute__((aligned(4), section("__DATA," SECTION)))
|
||||
#define PLACE_IN_SECTION(SECTION) _SECTION_ATTR_IMPL_GENERIC(SECTION, __COUNTER__)
|
||||
|
||||
#define _SECTION_ATTR_SYMBOL_DECL_GENERIC(TYPE, SECTION_NAME) \
|
||||
static const TYPE *_##SECTION_NAME##_start_ptr; \
|
||||
@@ -278,11 +278,10 @@ FORCE_INLINE_ATTR TYPE& operator<<=(TYPE& a, int b) { a = a << b; return a; }
|
||||
|
||||
#else /* ELF targets (Linux and embedded) */
|
||||
|
||||
#define PLACE_IN_SECTION(SECTION) \
|
||||
__attribute__((used, aligned(4), section("." SECTION)))
|
||||
|
||||
#define _SECTION_ATTR_IMPL_GENERIC(SECTION, COUNTER) \
|
||||
__attribute__((aligned(4), section("." SECTION "." _COUNTER_STRINGIFY(COUNTER))))
|
||||
__attribute__((used, aligned(4), section("." SECTION "." _COUNTER_STRINGIFY(COUNTER))))
|
||||
|
||||
#define PLACE_IN_SECTION(SECTION) _SECTION_ATTR_IMPL_GENERIC(SECTION, __COUNTER__)
|
||||
|
||||
#define _SECTION_ATTR_SYMBOL_DECL_GENERIC(TYPE, SECTION_NAME) \
|
||||
extern TYPE _##SECTION_NAME##_start; \
|
||||
|
||||
@@ -8,3 +8,9 @@ components/esp_common/test_apps/esp_common:
|
||||
depends_components:
|
||||
- esp_common
|
||||
- esp_system # Defines the section placement for attributes
|
||||
|
||||
components/esp_common/test_apps/section_macros:
|
||||
enable:
|
||||
- if: IDF_TARGET == "linux"
|
||||
depends_components:
|
||||
- esp_common
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
set(COMPONENTS main)
|
||||
|
||||
project(test_section_macros)
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Linker script for the section macros test on Linux host builds.
|
||||
* Collects all uint32_t entries placed in the .test_data_table section.
|
||||
*/
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.test_data_table :
|
||||
{
|
||||
PROVIDE(_test_data_table_start = .);
|
||||
KEEP(*(SORT(.test_data_table*)))
|
||||
PROVIDE(_test_data_table_end = .);
|
||||
}
|
||||
}
|
||||
INSERT AFTER .data;
|
||||
@@ -0,0 +1,11 @@
|
||||
idf_component_register(SRCS "test_section_macros.c" "test_entries_a.c" "test_entries_b.c"
|
||||
INCLUDE_DIRS "."
|
||||
WHOLE_ARCHIVE)
|
||||
|
||||
if(CONFIG_IDF_TARGET_LINUX AND NOT CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
|
||||
# Add linker script that collects the .test_data_table section
|
||||
# On macOS, custom sections are handled via Mach-O __DATA segments
|
||||
# and do not require linker scripts (which use GNU ld -T syntax).
|
||||
target_link_options(${COMPONENT_LIB} INTERFACE
|
||||
"-Wl,-T,${CMAKE_CURRENT_LIST_DIR}/../ld/test_section.ld")
|
||||
endif()
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_attr.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* Three entries placed in the test_data_table section from translation unit A.
|
||||
* The test verifies these values are discoverable at link time.
|
||||
*/
|
||||
static const uint32_t entry_a1 PLACE_IN_SECTION("test_data_table") = 0xDEADBEEF;
|
||||
static const uint32_t entry_a2 PLACE_IN_SECTION("test_data_table") = 0xCAFEBABE;
|
||||
static const uint32_t entry_a3 PLACE_IN_SECTION("test_data_table") = 0x12345678;
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_attr.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* Two entries placed in the test_data_table section from a DIFFERENT
|
||||
* translation unit. This verifies the linker collects entries across
|
||||
* multiple object files.
|
||||
*/
|
||||
static const uint32_t entry_b1 PLACE_IN_SECTION("test_data_table") = 0xAAAAAAAA;
|
||||
static const uint32_t entry_b2 PLACE_IN_SECTION("test_data_table") = 0x55555555;
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "esp_attr.h"
|
||||
|
||||
/*
|
||||
* Test for the portable link-time section macros defined in esp_attr.h.
|
||||
*
|
||||
* Two separate translation units (test_entries_a.c and test_entries_b.c)
|
||||
* place uint32_t values into the "test_data_table" section using
|
||||
* PLACE_IN_SECTION(). This main function uses _SECTION_ATTR_SYMBOL_DECL_GENERIC
|
||||
* and _SECTION_START/_SECTION_END to iterate the collected entries and verify:
|
||||
* 1. The total count matches the expected number (5 entries).
|
||||
* 2. Every expected value is present in the section.
|
||||
*/
|
||||
|
||||
_SECTION_ATTR_SYMBOL_DECL_GENERIC(uint32_t, test_data_table)
|
||||
|
||||
/* Expected values — order is linker-determined, so we check membership */
|
||||
static const uint32_t expected_values[] = {
|
||||
0xDEADBEEF,
|
||||
0xCAFEBABE,
|
||||
0x12345678,
|
||||
0xAAAAAAAA,
|
||||
0x55555555,
|
||||
};
|
||||
|
||||
#define EXPECTED_COUNT (sizeof(expected_values) / sizeof(expected_values[0]))
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
const uint32_t *start = _SECTION_START(test_data_table);
|
||||
const uint32_t *end = _SECTION_END(test_data_table);
|
||||
|
||||
/* --- Check 1: entry count -------------------------------------------- */
|
||||
size_t count = (size_t)(end - start);
|
||||
printf("Section entry count: %zu (expected %zu)\n", count, (size_t)EXPECTED_COUNT);
|
||||
|
||||
if (count != EXPECTED_COUNT) {
|
||||
printf("FAIL: entry count mismatch\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* --- Check 2: every expected value is present ------------------------ */
|
||||
for (size_t i = 0; i < EXPECTED_COUNT; i++) {
|
||||
int found = 0;
|
||||
for (size_t j = 0; j < count; j++) {
|
||||
if (start[j] == expected_values[i]) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
printf("FAIL: expected value 0x%08X not found in section\n", expected_values[i]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* --- Check 3: no unexpected values ----------------------------------- */
|
||||
for (size_t j = 0; j < count; j++) {
|
||||
int known = 0;
|
||||
for (size_t i = 0; i < EXPECTED_COUNT; i++) {
|
||||
if (start[j] == expected_values[i]) {
|
||||
known = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!known) {
|
||||
printf("FAIL: unexpected value 0x%08X found in section\n", start[j]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
printf("SUCCESS: All %zu section entries verified.\n", count);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
|
||||
|
||||
@pytest.mark.host_test
|
||||
@idf_parametrize('target', ['linux'], indirect=['target'])
|
||||
def test_section_macros(dut: Dut) -> None:
|
||||
dut.expect('SUCCESS: All 5 section entries verified.')
|
||||
|
||||
|
||||
@pytest.mark.host_test
|
||||
@pytest.mark.macos
|
||||
@idf_parametrize('target', ['linux'], indirect=['target'])
|
||||
def test_section_macros_macos(dut: Dut) -> None:
|
||||
dut.expect('SUCCESS: All 5 section entries verified.')
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_IDF_TARGET="linux"
|
||||
Reference in New Issue
Block a user