«а давайте… давайте… давайте дадим инструменты, но поломаные, но снаружи хорошие, и никому не скажем, что они поломаные, ахахахахаха!» пидорасы. в самом плохом смысле.
вот в гоцэцэ можно брать адреса меточек, а потом на эти адреса делать прямое goto. вроде бы круто, да? ну, извращение, но если надо быструю виртуальную машину с минимальным диспетчером опкодов, а в асм по каким-то причинам нельзя — то вполне вариант, компилируется в три асм-команды. примеров в сети есть.
а теперь мы хотим то же самое, только джампать внутрь функций. а почему нельзя? параметров функции не принимают, локалов не используют. а мне удобно описывать примитивы как отдельные функции, чтобы можно было ядро расширять. и вот тут гоцэцэ начинает считать, что он просто охуеть умный какой.
void *fuck_you_gcc (void) {
return &&mylabel;
mylabel:
что-то-там
goto **IP++;
}
круто, да? ну можно же? а вот хуй. сначала гоцэцэ матерится, что я, де, возвращаю указатель на локальную метку. блядь, да, прикинь: именно это я и хотел сделать! матерится, кстати, ворнингом, не еггогом. ладно. успокаиваем дегенерата.
void *fuck_you_gcc (void) {
static const fuck_you_gcc_again[1] = {&&mylabel};
return (void *)fuck_you_gcc_again[0];
mylabel:
что-то-там
goto **IP++;
}
на удивление, хвалёный data flow analysis тут каким-то образом умудряется обосраться и ничего не заметить. ворнинг пропал. но… нихуя не работает. потому что хвалёный data flow analysis обосрался. гоцэцэ считает, что метка, и всё, что за ней, не используется — и возвращает вместо адреса метки почему-то адрес входа в функцию. я хуй знает, почему он посчитал, что это «оптимизация, которая не меняет смысл программы». видимо, потому что гладиолус. ладно. обходим.
static volatile int fuck_you_gcc_agan_and_again;
void *fuck_you_gcc (void) {
static const fuck_you_gcc_again[1] = {&&mylabel};
if (fuck_you_gcc_agan_and_again == 0) {
mylabel:
что-то-там
goto **IP++;
}
return (void *)fuck_you_gcc_again[0];
}
переменную в глобальном ините ставим в неноль, потом зовём функцию (да, кстати: такой изврат с вызовом потому что иначе-то никак адрес метки не получить, она ж локальная). ура, адрес метки правильный, но… нихуя не работает. потому что опизденеть какой умный гоцэцэ… блядь, вот не угадаете. даю паузу.
ладно, всё равно никто даже не пытался. короче, несмотря на то, что IP — глобал, что я его даже пометил volatile — ебаный гоцэцэ решил, что этот гото может прыгнуть исключительно на эту метку, и больше никуда. ведь других меток в функции нет. поэтому он заменил индирект на простое «jmp mylabel». ай, бля, красава, ай, бля, спасибо! это, видимо, снова Охуительная Не Меняющая Смысл Кода Оптимизация. попытки прояснить гоцэцэ при помощи трюков встроеного асма закономерно не работают. ладно. всовываем всем в жопу лом.
static volatile int fuck_you_gcc_agan_and_again;
void *fuck_you_gcc (void) {
static const fuck_you_gcc_again[2] = {&&mylabel, &&fuck_gcc_developers_with_long_crowbar};
if (fuck_you_gcc_agan_and_again == 0) {
mylabel:
что-то-там
goto **IP++;
}
fuck_gcc_developers_with_long_crowbar:
return (void *)fuck_you_gcc_again[0];
}
вы не поверите, но на этом месте гоцэцэ устал со мной бодаться и сгенерировал именно тот код, которого я от него добивался. ура, у нас же теперь АЖ ЦЕЛЫХ ДВЕ МЕТОЧКИ, значит гото нельзя «оптимизировать»! то, что вторая не используется — гоцэцэ, к счастью, не заметил.
да, здесь денегераты со «стандартом» в верхней жопе начнут мне рассказывать, что использование адреса метки вне функции, где она определена — это UB, а потому гоцэцэ имеет право на всё вышеописаное. с этими существами я спорить не буду по причине отсутствия у них мыслительного органа.
если чо, всю эту хуйню гоцэцэ делает даже с -O0. не то чтобы оно было важно, потому что нахера мне быстрая VM при -O0, но отмечу на всякий случай.
p.s.: ответ на вопрос, который никто не задавал: «почему не использовать просто адреса фнукций, там же всё равно нет аргументов и локалов?» потому что при каких-то странных условиях гоцэцэ иногда им зачем-то всё равно приписывает пролог и эпилог. я не очень понял, что является триггером, но. соответственно, `goto` эпилог не делает, и стек улетает в гости к венерианским сисястым шлюхам. (дополнение: это может быть пиздёж с моей стороны, вызваный Тяжёлыми Обстоятельствами. но я всё равно изначально хотел объединять несколько примитивов в один «пакет», и всё равно засунуть их все в одну функцию не выйдет, их там за триста штук, и они всё равно могут джампать наружу из функции.) |