Как сообщить компилятору GCC, что код должен генерироваться последовательно, т. е. без переходов

Как сообщить компилятору GCC, что код должен генерироваться последовательно, то есть без переходов.

Я работаю над проектом, который встраивает встроенную сборку в исходный код C (или LLVM IR).

Моя реализация зависит от кода между встроенной сборкой, которая будет записана в исполняемый файл как есть.

Более формально, предположим, что у меня есть исходный код (C или LLVM IR):

.label_start: (inserted as inline assembly)
inline_assembly0
source_code0
source_code1
inline_assembly1
...
.label_end: (inserted as inline assembly)
...

Теперь это не должно быть скомпилировано как:

.jmp_target:
source_code1
inline_assembly1
...
.label_end: (inserted as inline assembly)
...

.label_start: (inserted as inline assembly)
inline_assembly0
source_code0
jmp jmp_target

т.е. код должен оставаться между метками без переупорядочения прыжков .label_start и .label_end.

Есть ли способ сообщить GCC, что все между двумя встроенными метками сборки должно оставаться «неповрежденным» без изменения порядка? Моя реализация зависит от этого.


person Shuzheng    schedule 11.05.2017    source источник
comment
Находится ли этот сегмент кода внутри цикла?   -  person Ben Voigt    schedule 11.05.2017
comment
зачем вам это? В любом случае у вас есть ЦП, который не выполняет внеочередное выполнение.   -  person Paul Floyd    schedule 11.05.2017
comment
В общем, код может быть внутри цикла @BenVoigt.   -  person Shuzheng    schedule 11.05.2017
comment
Потому что я вычисляю контрольную сумму по диапазону, определяемому двумя метками во время выполнения, чтобы защитить приложение от несанкционированного доступа @PaulFloyd.   -  person Shuzheng    schedule 11.05.2017
comment
Похоже на проблему XY. Если вам нужна определенная последовательность машинного кода, используйте язык ассемблера. Но сначала вы должны понять, почему вам это нужно, и в первую очередь использовать C, если вы не можете доказать, что C недостаточно.   -  person too honest for this site    schedule 11.05.2017
comment
@ Олаф - я не могу этого сделать. Я изменяю существующий исходный код, который я, возможно, не написал программно.   -  person Shuzheng    schedule 11.05.2017


Ответы (2)


Насколько я понимаю ваш вопрос, в руководстве по GCC есть несколько слов о это (выделение добавлено).

Обратите внимание, что компилятор может перемещать даже изменчивые инструкции asm относительно другого кода, в том числе между инструкциями перехода. Например, на многих таргетах есть системный регистр, управляющий режимом округления операций с плавающей запятой. Установка его с помощью изменчивого asm, как в следующем примере PowerPC, не работает надежно.

asm volatile("mtfsf 255, %0" : : "f" (fpenv));
sum = x + y;

Компилятор может переместить добавление назад перед volatile asm. Чтобы заставить его работать должным образом, добавьте искусственную зависимость к asm, сославшись на переменную в последующем коде, например:

asm volatile("mtfsf 255,%1" : "=X" (sum) : "f" (fpenv));
sum = x + y;

По сути, вам нужно «фиктивное использование», чтобы предотвратить изменение порядка.

Мы также используем такие вещи в Mono, чтобы продлить жизнь ссылки в низкоуровневом коде сборщика мусора, гарантируя, что она не будет преждевременно освобождена, если сборщик мусора прервет подпрограмму:

static inline void dummy_use (void *v)
    __asm__ volatile ("" : "=r"(v) : "r"(v));
}
person Jon Purdy    schedule 11.05.2017
comment
Это касается порядка выполнения, но вопрос обсуждает расположение памяти - person Ben Voigt; 11.05.2017
comment
Спасибо, это было очень информативно! Но обеспечивает ли это распределение памяти? - person Shuzheng; 11.05.2017
comment
@Shuzheng: Не совсем так, как говорит Бен Фойгт, это только позволяет вам убедиться, что код выполняется в определенном порядке. Например, холодная ветвь все еще может быть перемещена вне очереди. В общем, я думаю, вам нужно сделать что-то вроде #pragma GCC push_options, #pragma GCC optimize ("O0"), …, #pragma GCC pop_options, чтобы локально отключить все оптимизации. (-fno-reorder-blocks может быть достаточно.) Вы также можете использовать встроенный ассемблер для всего в этих блоках, если это возможно для вас. - person Jon Purdy; 11.05.2017
comment
@JonPurdy - это не так, потому что некоторый код между метками может быть LLVM IR или C. Итак, мне нужно преобразовать исходный код во встроенную сборку. Кроме того, встроенный ассемблер для всего можно переупорядочить, верно? (Используя прыжки) - person Shuzheng; 11.05.2017

попробуйте отключить оптимизацию, gcc -O0 source.c

person sailfish009    schedule 11.05.2017