LINUX.ORG.RU

Const значение в rodata

 , ,


0

2

Прочитал такую статью: https://dzen.ru/a/Ys_GysRGngbcr_H6 Для тех, кто не любит ходить по ссылкам, пересказываю суть проблемы:в программе

#include <stdio.h>

int main(void) {
    const int value = 111;
    printf("init value: %d\n", value);
    *((int*) &value) = 222;
    printf("new  value: %d\n", value);
    return(0);
}

Значение value не размещается в секции rodata, как заставить компилятор туда его разместить?



Последнее исправление: Sergeyka (всего исправлений: 1)

Ответ на: комментарий от Werenter

Неа, у меня больше академический интерес, проверял только здесь: https://www.onlinegdb.com/online_c_compiler. Вообще, пишут, что const проверяется только во время компиляции, а в рантайме нет, хотя иногда компилятор размещает const переменные в секции rodata, а иногда нет, как сейчас, интересует когда он это делает, а когда нет.

Sergeyka
() автор топика

Так а что странного? Тут явно используется приведение к указателю (без константности) и присваивание значения по этому указателю. Неопределенное поведение на то и неопределенное, что хз, как оно будет себя вести.

rumgot ★★★★★
()
Ответ на: комментарий от no-such-file

Но вот здесь же C with C++, static non-const, void* casts, segfault Компилятор разместил const значение в секции rodata, пробовал использовать static, но тогда программа выводит только одно значение и завершается без ошибок. Так можно это ub избежать?

Sergeyka
() автор топика
Ответ на: комментарий от Sergeyka

Никак в стандарте черным по белому написано, то изменение const приводит к UB. А про rodata стандарт ничего не говорит, это компиляторы, поэтому если хочешь ответа на свой вопрос, то смотри документацию к компилятору, причем к своей версии.

soomrack ★★★★
()

Проверил на godbolt. clang выбросил эту переменную, заинлайнил значение 111 в первый и второй printf и выбросил присваивание.

В принципе всё правильно сделал на мой взгляд.

Поэтому конкретизируй, чего ты хочешь добиться.

vbr ★★★
()

Если отвечать на конкретно твой вопрос, можно попробовать так сделать:

#include <stdio.h>

int main(void) {
    __attribute__((section(".rodata")))
    static int value = 111;
    printf("init value: %d\n", value);
    *((int*) &value) = 222;
    printf("new  value: %d\n", value);
    return(0);
}

Уж не знаю, зачем тебе это надо.

vbr ★★★
()
Ответ на: комментарий от AntonI

Оно много от чего зависит, еще от того как ты меняешь этот const, через передачу указателя на этот const в функцию или как ТС. Я сообразительным студентам давал такие задания типа «найди ошибку», для выработки навыка «не писать мудацкий код».

soomrack ★★★★
()

скалярные константы компилятор вообще нигде не обязан размещать. он их подставляет там, где они используются. структурные константы, например си строки и проч, он будет размещать в ro секции.

зачем компилятору тратить память задачи, если он может просто подставить 111 там, где оно используется.

alysnix ★★★
()

Чтобы поместить переменную в определённую секцию, нужно либо использовать __attribute__ ((section("..."))) (https://gcc.gnu.org/onlinedocs/gcc/extensions-to-the-c-language-family/specifying-attributes-of-variables.html#var-attr-section-section-name), либо писать на (inline) ассембелере. На уровне языков C и C++ никаких секций не существует, это детали реализации конкретной платформы.

annulen ★★★★★
()
Последнее исправление: annulen (всего исправлений: 1)

Правильный способ проверки, в какую секцию компилятор помещает значение — написать минимальный корректный (без UB и прочей жести) пример кода и дизассемблировать бинарник.

annulen ★★★★★
()
Ответ на: комментарий от Sergeyka

Компилятор разместил const значение в секции rodata

Конкретная версия конкретного компилятора с конкретными флагами на конкретном процессоре. Никаких гарантий как это будет работать если что-то изменится нет. Что тебе непонятно в фразе UB?

no-such-file ★★★★★
()
Ответ на: комментарий от hateyoufeel

А как определить, есть ли в программе UB? Учитывая, что переполнение int потенциально возможно в большинстве программ, то и UB присутствует в них. И компилятор может с полным правом сделать любую дичь, если где-то в коде есть (x + 1) для int?

А есть более-менее полный список UB? https://en.cppreference.com/w/cpp/language/ub дает весьма куцый список примеров.

blex ★★
()

Попробуй static const, а не просто const. Переменная у тебя, конечно const, но по идее она так же на стеке размещается (если компилятор не будет делать оптимизации и просто инлайнить её значение по месту использования). То что размещено на стеке попасть в rodata никак не может.

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 2)
Ответ на: комментарий от blex

А как определить, есть ли в программе UB? Учитывая, что переполнение int потенциально возможно в большинстве программ, то и UB присутствует в них. И компилятор может с полным правом сделать любую дичь, если где-то в коде есть (x + 1) для int?

Ну не любую, изменения int x=0xEFFFFFFF; x++ ограничены storage x (областью хранения x). А для unsigned int overflow не бывает, т.к. все вычисления делаются по модулю.

А есть более-менее полный список UB?

Сам по себе список в отрыве от контекста бессмысленен и непонятен. Все перечислено в стандарте.

soomrack ★★★★
()
Ответ на: комментарий от blex

И компилятор может с полным правом сделать любую дичь, если где-то в коде есть (x + 1) для int?

Только в той ветке, где есть переполнение.

Например, есть код for(int i = x; i < x + 10; i++) .... Компилятор вправе заменить на повторение 10 раз. Потому что либо x + 10 переполнения не вызывает и тогда будет 10 повторов, либо переполнение (из-за которого, по идее, цикл вообще ни разу не выполнится) = UB и можно делать что угодно.

monk ★★★★★
()

Переменная int value размещена на стеке функции main(), поэтому const будет отрабатываться софтверно во время выполнения программы, тем кодом, который сгенерирует компилятор.

В секцию можно помещать только переменные, которые размещаются статически (перед нчалом выполнения программы), например, загрузчиком приложения. Поэтому, вынеси переменную за пределы main() или напиши перед ней ключевое слово static (оно неявно сделает то же самое, поместит value в статическую область приложения).

Vic
()
Последнее исправление: Vic (всего исправлений: 1)
Ответ на: комментарий от Sergeyka

Когда время жизни статическое, емнип. Добавь static и/или сделай глобальным. Хотя статик не поможет: внутри функции инициализация при первом обращении. Всё глобальное или уровня единицы трансляции имеет один адрес и может поместиться внутрь секции. Для .bss всё аналогично.

hatred ★★★
()