" Когда сами константы становятся переменными. "

Пролог

В этом тексте я расскажу про одну полезную и широко распространенную утилиту для калибровки микроконтроллерных прошивок под названием TunerPRO.

Стандарт программирования ISO-26262 требует раздельного хранения калибровочных данных, конфигурационных данных и кода внутри прошивки. Это требование возникло не на пустом месте, а как раз для того, чтобы после выпуска релиза с программой можно было проводить гибкую товарную политику. Для этого и была разработана программа TunerPRO.

TunerPRO - это бесплатный бинарный редактор прошивок. По своей сути это функциональный аналог утилиты STM32Studio, только для любого микроконтроллера.
Эта программа позволит вам редактировать константы в готовом .bin файле. Минуя стадию повторной пересборки всего проекта прошивки (компиляции и компоновки). Можно сказать, что TunerPRO - хакерская tool-а. Ещё TunerPRO позволяет сравнивать bin файлы.

Эта утилита связывает воедино всю информацию про переменные: глобальные и константы. В данном случае константы. Это адрес ячейки памяти в bin-аре, размерность переменной, размер параметра, формат ее хранения в памяти, имя переменной, множитель, единицу измерения, максимальное и минимальное значение. В то время как map файл дает только инфу про имя ,адрес в памяти и размер.

Определения

Параметр - это переменная, которая помимо адреса в памяти, значения и размера несет в себе ещё и метаданные про физическую величину, размерность, тип данных, единицы измерения, множитель, тип доступа, формат записи и прочее, и прочее.

patch - (заплатка) - маленькое изменение в коде или в бинарном файле.

метаданные - информация о другой информации, или данные, относящиеся к дополнительной информации о содержимом или объекте. Метаданные раскрывают сведения о признаках и свойствах, характеризующих какие-либо сущности, позволяющие автоматически искать и управлять ими в больших информационных потоках.

XDF Файл - Данный файл содержит информацию о параметрах, адреса таблиц и их параметры, числовые константы, функции и др., что позволяет визуализировать калибровки прошивки в программе, чтобы иметь возможность интуитивно понятно редактировать прошивку прибора. Это родной формат для утилиты TunerPro. XDF-файл должен четко подходить к прошивке вашего прибора. Xdf это база данных про переменные в компьютерной программе. В высшем своем проявлении этот файл говорит как интерпретировать каждый байт в бинарном файле с прошивкой.

Вот пример реального XDF файла

<!-- Written 11/15/2025 14:38:18 -->
<XDFFORMAT version="1.80">
  <XDFHEADER>
    <flags>0x1</flags>
    <fileversion>&quot;ver 1&quot;</fileversion>
    <deftitle>nucleo_f401re_esp_01</deftitle>
    <description>ARM CORTEX_M4</description>
    <author>aabzel</author>
    <BASEOFFSET offset="0" subtract="0" />
    <DEFAULTS datasizeinbits="8" sigdigits="2" outputtype="2" signed="1" lsbfirst="0" float="0" />
    <REGION type="0xFFFFFFFF" startaddress="0x0" size="0x80000" regioncolor="0x0" regionflags="0x0" name="Binary File" desc="This region describes the bin file edited by this XDF" />
  </XDFHEADER>
  <XDFCONSTANT uniqueid="0x6298" flags="0xC">
    <title>tuner_pro_s8</title>
    <CATEGORYMEM index="0" category="1" />
    <EMBEDDEDDATA mmedtypeflags="0x01" mmedaddress="0x3461C" mmedelementsizebits="8" mmedmajorstridebits="0" mmedminorstridebits="0" />
    <outputtype>2</outputtype>
    <rangehigh>120.000000</rangehigh>
    <rangelow>-120.000000</rangelow>
    <datatype>3</datatype>
    <unittype>2</unittype>
    <DALINK index="0" />
    <MATH equation="X">
      <VAR id="X" />
    </MATH>
  </XDFCONSTANT>
  <XDFCONSTANT uniqueid="0x4478">
    <title>tuner_pro_float</title>
    <EMBEDDEDDATA mmedtypeflags="0x10002" mmedaddress="0x34624" mmedelementsizebits="32" mmedmajorstridebits="0" mmedminorstridebits="0" />
    <datatype>2</datatype>
    <unittype>3</unittype>
    <DALINK index="0" />
    <MATH equation="X">
      <VAR id="X" />
    </MATH>
  </XDFCONSTANT>
  <XDFCONSTANT uniqueid="0x5C94" flags="0xC">
    <title>tuner_pro_u8</title>
    <EMBEDDEDDATA mmedaddress="0x34614" mmedelementsizebits="8" mmedmajorstridebits="0" mmedminorstridebits="0" />
    <outputtype>2</outputtype>
    <rangehigh>200.000000</rangehigh>
    <datatype>3</datatype>
    <unittype>3</unittype>
    <DALINK index="0" />
    <MATH equation="X">
      <VAR id="X" />
    </MATH>
  </XDFCONSTANT>
</XDFFORMAT>

Входные данные для утилиты TunerPro

Тип файла

Расширение

Тип файла

Пояснение

binary file

bin

бинарный

Файл с прошивкой

bin definition file

XDF

текстовый

Аналог map файла

XDF файлы можно генерировать из MATLAB файлов, т.к. только там есть физический смысл переменной. XDF файлы чем-то похоже на a2l файлы из протокола XCP.

Информацию про названия глобальных константных переменных их размер и расположение в физической памяти можно выделить из *.elf файла командой read elf. Буквально одной строчкой.

readelf -a  firmware.elf | grep OBJECT  | grep GLOBAL | grep  "DEFAULT    1"

C:\projects\debug\source\projects\nda\build>readelf -a  nda.elf | grep OBJECT  | grep GLOBAL | grep  "DEFAULT    1"
  6502: 010747f8    40 OBJECT  GLOBAL DEFAULT    1 __mprec_tinytens
  6687: 01072268   240 OBJECT  GLOBAL DEFAULT    1 CanConfig
  6725: 01072178    16 OBJECT  GLOBAL DEFAULT    1 SysTickConfig
  6750: 0106e6e4     8 OBJECT  GLOBAL DEFAULT    1 ClockInfo
  6836: 01072f68    60 OBJECT  GLOBAL DEFAULT    1 CliConfig
  6849: 010712c8   336 OBJECT  GLOBAL DEFAULT    1 ClockReg
  6931: 01072188    16 OBJECT  GLOBAL DEFAULT    1 SuperCycleConfig
  6976: 0106f88c   512 OBJECT  GLOBAL DEFAULT    1 crc16LookUpTable
  6997: 01073810   608 OBJECT  GLOBAL DEFAULT    1 GpioConfig
  7021: 01071c28   120 OBJECT  GLOBAL DEFAULT    1 PortReg
  7061: 01074730   200 OBJECT  GLOBAL DEFAULT    1 __mprec_tens
  7066: 0106e9b4   840 OBJECT  GLOBAL DEFAULT    1 s_aFlexCan_Norma[...]
  7072: 01073010   144 OBJECT  GLOBAL DEFAULT    1 LedMonoConfig
  7109: 01072258     8 OBJECT  GLOBAL DEFAULT    1 StoreFsConfig
  7255: 01071ce4    16 OBJECT  GLOBAL DEFAULT    1 ClockOutConfig
  7269: 01072fa4   108 OBJECT  GLOBAL DEFAULT    1 LittleFsConfig
  7281: 01074294     4 OBJECT  GLOBAL DEFAULT    1 _global_impure_ptr
  7311: 01074708    40 OBJECT  GLOBAL DEFAULT    1 __mprec_bigtens
  7395: 01071bd4    84 OBJECT  GLOBAL DEFAULT    1 GpioReg
  7400: 010731e8    84 OBJECT  GLOBAL DEFAULT    1 WriterConfig
  7408: 0106ef2c   540 OBJECT  GLOBAL DEFAULT    1 CanReg
  7543: 0107452c    32 OBJECT  GLOBAL DEFAULT    1 __sf_fake_stderr
  7599: 0107323c    20 OBJECT  GLOBAL DEFAULT    1 CoreConfig
  7603: 01070094    16 OBJECT  GLOBAL DEFAULT    1 SwComponentConfig
  7622: 0106ecfc   560 OBJECT  GLOBAL DEFAULT    1 s_aFlexCan_DataB[...]
  7652: 01072198    24 OBJECT  GLOBAL DEFAULT    1 BoardConfig
  7657: 01071d44    80 OBJECT  GLOBAL DEFAULT    1 RamSectorConfig
  7666: 01071cf4     0 OBJECT  GLOBAL DEFAULT    1 DmaConfig
  7672: 010721b0   168 OBJECT  GLOBAL DEFAULT    1 Wires
  7687: 01070108   864 OBJECT  GLOBAL DEFAULT    1 test_list
  7713: 01071cf4    48 OBJECT  GLOBAL DEFAULT    1 FlashSectorConfig
  7757: 01073170   120 OBJECT  GLOBAL DEFAULT    1 UartConfig
  7788: 01074628    96 OBJECT  GLOBAL DEFAULT    1 __month_lengths
  7796: 010730f0   120 OBJECT  GLOBAL DEFAULT    1 StringReaderConfig
  7850: 01073768   168 OBJECT  GLOBAL DEFAULT    1 PinConfig
  7903: 01071cd0    20 OBJECT  GLOBAL DEFAULT    1 BootConfig
  7962: 01073168     6 OBJECT  GLOBAL DEFAULT    1 TimeConfig
  7978: 0107454c    32 OBJECT  GLOBAL DEFAULT    1 __sf_fake_stdin
  7993: 01071fb0   456 OBJECT  GLOBAL DEFAULT    1 ParamArray
  8018: 01071d94   540 OBJECT  GLOBAL DEFAULT    1 InterruptConfig
  8281: 01072358   640 OBJECT  GLOBAL DEFAULT    1 CanMessageBuffer[...]
  8335: 01071d24    32 OBJECT  GLOBAL DEFAULT    1 FlashConfig
  8346: 01074614    12 OBJECT  GLOBAL DEFAULT    1 _C_numeric_locale
  8366: 01073250  1304 OBJECT  GLOBAL DEFAULT    1 IntNumInfo
  8427: 010730c4    20 OBJECT  GLOBAL DEFAULT    1 PostponeFunConfig
  8483: 01073a70     5 OBJECT  GLOBAL DEFAULT    1 LogConfig
  8583: 0107456c    32 OBJECT  GLOBAL DEFAULT    1 __sf_fake_stdout
  8605: 01074190   257 OBJECT  GLOBAL DEFAULT    1 _ctype_
  8622: 0106f4e4   208 OBJECT  GLOBAL DEFAULT    1 SystemInitInstance
  8635: 01071b1c   120 OBJECT  GLOBAL DEFAULT    1 FlashRegisters
  8693: 0106e920    12 OBJECT  GLOBAL DEFAULT    1 UartRegs

Что надо из ПО?

Название утилиты

Назначение

ST-LINK_CLI.exe

Для загрузки прошивки

TunerPro.exe

Для редактирования бинаря

WinMerge.exe

Для сравнения файлов: текстовых и бинарных

Практическая часть

Посмотрим, как работает утилита TunerPro. Вот я накропал простецкий модульный тест, который просто печатает константы из Flash памяти.

#include "test_tuner_pro.h"

#include "log.h"
#include "unit_test_check.h"
#include "array_diag.h"

 const char tuner_pro_text[16] = "test_data";
 const uint8_t tuner_pro_u8 = 0x12;
 const uint16_t tuner_pro_u16 = 0x1234;
 const uint32_t tuner_pro_u32 = 0x12345678;
 const int8_t tuner_pro_s8 = -8;
 const int16_t tuner_pro_s16 = -16;
 const int32_t tuner_pro_s32 = -32;
 const float tuner_pro_float = 5.5;
 const double tuner_pro_double = 7.7;

/*
 tr tuner_pro+
 */
bool test_tuner_pro_types(void) {
    bool res = true;
    LOG_DEBUG(SYS, "%s():", __FUNCTION__);
    EXPECT_EQ(1, sizeof(tuner_pro_u8));
    EXPECT_EQ(1, sizeof(tuner_pro_s8));
    EXPECT_EQ(2, sizeof(tuner_pro_s16));
    EXPECT_EQ(2, sizeof(tuner_pro_u16));
    EXPECT_EQ(4, sizeof(tuner_pro_s32));
    EXPECT_EQ(4, sizeof(tuner_pro_u32));
    EXPECT_EQ(4, sizeof(tuner_pro_float));
    EXPECT_EQ(8, sizeof(tuner_pro_double));
    EXPECT_EQ(16, sizeof(tuner_pro_text));
    return res;
}

bool test_tuner_pro_vals(void) {
    bool res = true;
    LOG_DEBUG(SYS, "%s():", __FUNCTION__);
    LOG_INFO(SYS, "U8:0x%x", tuner_pro_u8);
    LOG_INFO(SYS, "U16:0x%x", tuner_pro_u16);
    LOG_INFO(SYS, "U32:0x%x", tuner_pro_u32);
    LOG_INFO(SYS, "S8:%d", tuner_pro_s8);
    LOG_INFO(SYS, "S16:%d", tuner_pro_s16);
    LOG_INFO(SYS, "S32:%d", tuner_pro_s32);
    LOG_INFO(SYS, "f:%f", tuner_pro_float);
    LOG_INFO(SYS, "d:%f", tuner_pro_double);
    LOG_INFO(SYS, "text:[%s]", tuner_pro_text);
    return res;
}

bool test_tuner_pro_mem(void) {
    bool res = true;
    LOG_DEBUG(SYS, "%s():", __FUNCTION__);
    LOG_INFO(SYS, "U8:0x%s", ArrayToStr((uint8_t*)&tuner_pro_u8,sizeof(tuner_pro_u8)));
    LOG_INFO(SYS, "U16:0x%s", ArrayToStr((uint8_t*)&tuner_pro_u16,sizeof(tuner_pro_u16)));
    LOG_INFO(SYS, "U32:0x%s", ArrayToStr((uint8_t*)&tuner_pro_u32,sizeof(tuner_pro_u32)));
    LOG_INFO(SYS, "S8:0x%s", ArrayToStr((uint8_t*)&tuner_pro_s8,sizeof(tuner_pro_s8)));
    LOG_INFO(SYS, "S16:0x%s", ArrayToStr((uint8_t*)&tuner_pro_s16,sizeof(tuner_pro_s16)));
    LOG_INFO(SYS, "S32:0x%s", ArrayToStr((uint8_t*)&tuner_pro_s32,sizeof(tuner_pro_s32)));
    LOG_INFO(SYS, "tuner_pro_float:0x%s", ArrayToStr((uint8_t*)&tuner_pro_float,sizeof(tuner_pro_float)));
    LOG_INFO(SYS, "tuner_pro_double:0x%s", ArrayToStr((uint8_t*)&tuner_pro_double,sizeof(tuner_pro_double)));
    LOG_INFO(SYS, "tuner_pro_text:0x%s", ArrayToStr((uint8_t*)&tuner_pro_text,sizeof(tuner_pro_text)));
    return res;
}

bool test_tuner_pro_address(void) {
    bool res = true;
    LOG_DEBUG(SYS, "%s():", __FUNCTION__);
    LOG_INFO(SYS, "&tuner_pro_u8:0x%p", &tuner_pro_u8);
    LOG_INFO(SYS, "&tuner_pro_u16:0x%p", &tuner_pro_u16);
    LOG_INFO(SYS, "&tuner_pro_u32:0x%p", &tuner_pro_u32);
    LOG_INFO(SYS, "&tuner_pro_s8:0x%p", &tuner_pro_s8);
    LOG_INFO(SYS, "&tuner_pro_s16:0x%p", &tuner_pro_s16);
    LOG_INFO(SYS, "&tuner_pro_s32:0x%p", &tuner_pro_s32);
    LOG_INFO(SYS, "&tuner_pro_float:0x%p", &tuner_pro_float);
    LOG_INFO(SYS, "&tuner_pro_double:0x%p", &tuner_pro_double);
    LOG_INFO(SYS, "&tuner_pro_text:0x%p", tuner_pro_text);
    return res;
}

В результате исполнения я увидел

  1.348-->
  1.502-->tr tuner+
cmd_unit_test_run() argc 1
5.832,+5803,103 I,[TEST] key [tuner+]
5.834,+2,104 W,[TEST] unit_test_run_key() key tuner
************* Run test tuner_pro_types .1/49
!OKTEST
************* Run test tuner_pro_mem .2/49
6.140,+306,105 I,[SYS] U8:0x12
6.142,+2,106 I,[SYS] U16:0x3412
6.144,+2,107 I,[SYS] U32:0x78563412
6.146,+2,108 I,[SYS] S8:0xF8
6.148,+2,109 I,[SYS] S16:0xF0FF
6.150,+2,110 I,[SYS] S32:0xE0FFFFFF
6.152,+2,111 I,[SYS] tuner_pro_float:0x0000B040
6.154,+2,112 I,[SYS] tuner_pro_double:0xCDCCCCCCCCCC1E40
6.157,+3,113 I,[SYS] tuner_pro_text:0x746573745F6461746100000000000000
!OKTEST
************* Run test tuner_pro_const_vals .3/49
6.462,+305,114 I,[SYS] text:[U8:0x12,S8:-8,U16:0x1234,U32:0x12345678,S16:-16,S32:-32,f:5.500000,d:7.700000,text:[test_data],]
!OKTEST
************* Run test tuner_pro_vals .4/49
6.769,+307,115 I,[SYS] text:[U8:0x12,S8:-8,U16:0x1234,U32:0x12345678,S16:-16,S32:-32,f:5.500000,d:7.700000,text:[test_data],]
!OKTEST
************* Run test tuner_pro_address .5/49
7.076,+307,116 I,[SYS] &tuner_pro_u8:0x8034614
7.079,+3,117 I,[SYS] &tuner_pro_u16:0x8034616
7.081,+2,118 I,[SYS] &tuner_pro_u32:0x8034618
7.083,+2,119 I,[SYS] &tuner_pro_s8:0x803461c
7.086,+3,120 I,[SYS] &tuner_pro_s16:0x803461e
7.088,+2,121 I,[SYS] &tuner_pro_s32:0x8034620
7.090,+2,122 I,[SYS] &tuner_pro_float:0x8034624
7.093,+3,123 I,[SYS] &tuner_pro_double:0x8034628
7.095,+2,124 I,[SYS] &tuner_pro_text:0x8034604
!OKTEST
7.399,+304,125 I,[TEST] TestDuration:1565 ms=1.565 s=0.026083333 min
7.403,+4,126 I,[TEST] All 5 tests passed!

Теперь я закрываю IDE и далее работаю только с бинарём. Вот у меня есть *.bin прошивка. В ней есть глобальные переменные. Надо изменить константу без пере сборки всего проекта прошивки и залить эту модифицированную прошивку в flash память микроконтроллер.

Название константы

Адрес в памяти

bin file addr

Size

Начальное
значение

tuner_pro_s8

0x803461c

3461c

1

-8

tuner_pro_s16

0x803461e

3461e

2

-16

tuner_pro_s32

0x8034620

34620

4

-32

tuner_pro_text

0x8034604

34604

16

test_data

tuner_pro_double

0x8034628

34628

8

5.5

tuner_pro_float

0x8034624

34624

4

5.5

tuner_pro_u8

0x8034614

34614

1

0x12

tuner_pro_u16

0x8034616

34616

2

0x1234

tuner_pro_u32

0x8034618

34618

4

0x12345678

Сам файл XDF можно создать прямо внутри утилиты TunerPRO. Первым делом надо объявить заголовок. Открываем XDF -> XDF Header Editor. Тут надо только указать размер прошивки.

Затем вручную добавляем интересующие нас переменные. Одну за другой. XDF -> Create New XDF Parameter

Можно добавлять всяческие метаданные для переменной. Граничные значения, физическая величина, тип данных, единицы измерения, размерность, категорию и т. д. Всё то, про что не знал Си-компилятор. Эти метаданные кристаллизируется потом в XDF файле.

Утилита увидела в bin файле значение для переменной

Теперь мы можем преспокойно изменить циферку в переменной.

Чтобы занести изменения в bin файл нажимаем File-> Save Bin. Проверить наличие изменение можно в утилите WinMerge. Вот я внес patch в прошивку и это явно видно в bin файле.

Разницу между бинарями можно вычислить даже не выходя из TunerPRO инструментом Difference Tool

Осталось только просто прошить про патченый бинарь во flash память микроконтроллера STM32F401RE . В случае с STM32 микроконтроллером это делает утилита ST-LINK_CLI.exe

echo off
cls

set project_name=nucleo_f401re_esp_01_m
set project_dir=%cd%
 
set artefact_bin=%project_name%.bin
set FlashTool=ST-LINK_CLI.exe
set Device= 
set options=-c %Device%
set options= %options%  SWD freq=4000 
set options= %options%  HOTPLUG  LPM 
set options= %options%  -P %artefact_bin% 0x08000000
set options= %options%  -V "after_programming" 
set options= %options%  -Log -TVolt
call %FlashTool% %options%
rem Reset System
call %FlashTool% -Rst

 

Лог загрузки прошивки в память

У меня в прошивке есть UART-CLI. Поэтому я могу еще раз прогнать тот самый модульный тест и зарегистрировать изменения.

Как можно заметить, память в самом деле изменилась с 0x12 на 0x34. Другой вопрос почему printf оптимизировал и вывел старую прохардкоженную константу? Видимо это оптимизации компилятора. Но главное, что Flash память в самом деле изменилась в нужной ячейке!

Этот текст показывает как легко уязвимы .bin файлы. Все кому не лень могут их взять и подшаманить. В этом плане *.hex формат выглядит предпочтительнее так как в .hex для каждой строчки есть контрольная сумма.

TunerPRO можно иcпользовать как продвинутый hex editor.

Как это теперь применять на практике?

А вот как.

--Допустим вы пишите прошивку для какого-то прибора. И вам клиенты говорят, что нужна прошивка с измененными параметрами. В этом случае вы можете дать им ту же самую прошивку только прислать .xdf файл в котором или вы или они сами могут внести желаемое изменение.

--После старого проекта у вас не осталось сорцов. В наличии только устройство программатор и бинарь. При этом возникла потребность слегка модифицировать функционал. В одном месте. Тут вам снова поможет TunerPRO.

--Вам надо откалибровать какой-то агрегат. При этом пересборка прошивки с другими калибровочными константами занимает много времени. Ситуация осложняется тем что в прошивке нет ни UART-CLI ни NVRAM. В этом случае вы можете по крайней мере перебирать значения прямо в бинаре утилитой TunerPRO и пере накатывать новый артефакт. До тех пор пока не подберете нужную калибровку.

Достоинства Tuner PRO

++Эта утилита инвариантна к производителю микроконтроллера. Можно модифицировать прошивки для любого МК
++Это бесплатная утилита
++Утилита может интерпретировать базовые типы данных: float, uint8_t, int16_t и т. п.

Итог

Удалось получить представление о том, что такое утилита TunerPRO и как ей пользоваться.
Эта утилита позволяет вам переложить задачи калибровки с разработчика на пользователя прошивки. Вы просто даете .bin .xdf и пользователь уже сам настраивает прошивку так как требуется.

Словарь

Акроним

Расшифровка

XDF

extensible calibration definition format

MCU

microcontroller unit

IDE

integrated development environment

Gdb

GNU Debugger

elf

Executable and Linkable Format

Ссылки

Название

URL

Введение в TunerPRO RT

https://cobrartp.com/tunerpro-guide-by-cobrartp/#

TunerPro Quick guide

https://oldskulltuning.com/wp-content/uploads/2023/03/Quick-guide-rev1.4.pdf

UART-CLI

https://habr.com/ru/articles/694408/

STM Studio run-time variables monitoring and visualization tool for STM32 microcontrollers

https://www.st.com/en/development-tools/stm-studio-stm32.html

Вопросы
--Вот я собрал *.elf файл с прошивкой. Захотелось изменить одну константу перед загрузкой прошивки в MCU. Как мне теперь получить XDF Файл для утилиты TunerPRO? Надо создавать его вручную. Однако этот файл может генерировать MatLab, так как Simulink придает переменным физический смысл.

--XDF файл для утилиты TunerPRO это бинарный файл или текстовый файл? Текстовый

--Существует ли спецификация формата *.xdf файлов, чтобы корректным образом заполнить метаданные: заголовок, контрольную сумму и сами переменные?

--Как извлечь абсолютные адреса членов структур из *.elf файла? Gdb их же как-то достает?

--Может ли TunerPRO работать в консольном режиме?

--Как при программировании на Си отключить оптимизацию при printf печати константных переменных из flash памяти в GCC?

Комментарии (2)


  1. randomsimplenumber
    15.11.2025 15:54

    Но главное, что Flash память в самом деле изменилась в нужной ячейке!

    Главное что даже в своей собственной программе, с исходниками и адресами в elf файле, нельзя быть уверенным, что патч сработает именно так как хочется. Вот вы что то поменяли. Где то оно вроде как сработало, но не везде.


    1. aabzel Автор
      15.11.2025 15:54

      Моя гипотеза в том, что компилятор gcc при печати констант printf-ом переводил данные в сегмент text.