Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > GNU toolchain > встроенный асм, обработка исключений, на mingw


Автор: victor79 21.12.2008, 17:05
создаю код для обработки конструкции finally при исключениях:
Код

int doexceptedfinally(void) {}

#define finally(addr) \
   __asm__ ("pushl %0;     \
             pushl %%ebp;  \
             pushl %1;     \
             pushl %%fs:0; \
             movl  %%esp,%%fs:0;" \
             : : "g" (addr), "g" ((void*)&doexceptedfinally));

int test_finally1(void) {
      finally(&&end);
      *(int*)0 = 1;
      printf("это сообщение не возникнет\n");
end:
      printf("сообщение в test_finally1\n");
}

при компиляции получается такой код:
Код

        .file   "5.c"
        .text
.globl _doexceptedfinally
        .def    _doexceptedfinally;     .scl    2;      .type   32;     .endef
_doexceptedfinally:
        pushl   %ebp
        movl    %esp, %ebp
        popl    %ebp
        ret
        .section .rdata,"dr"
LC0:
        .ascii "\355\342\256 \341\256\256\241\351\245\255\250\245 \255\245 \242\256\247\255\250\252\255\245\342\12\0"
LC1:
        .ascii "\341\256\256\241\351\245\255\250\245 \242 test_finally1\12\0"
        .text
.globl _test_finally1
        .def    _test_finally1; .scl    2;      .type   32;     .endef
_test_finally1:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
/APP
        pushl $L3;
        pushl %ebp;
// сохраняется адрес вызова текущего обработчика
        pushl $_doexceptedfinally;
// сохраняется адрес EXCEPTION_REGISTRATION предыдущего обработчика
        pushl %fs:0;
// устанавливается новый обработчик
        movl  %esp,%fs:0;
/NO_APP
        movl    $1, 0
// !!!! портится адрес предыдущего обработчика !!!
//   т.к. он сейчас на вершине стека, а компилятор кажется не знает этого
        movl    $LC0, (%esp)
        call    _printf
L3:
        movl    $LC1, (%esp)
        call    _printf
        leave
        ret
        .def    _printf;        .scl    2;      .type   32;     .endef

здесь добавлены комментарии для понятности асмовского кода, и общая суть, что компилятор не знает, что я добавлял в стек значения и затирает в данном случае последнее добавленное (см комментарий к асм-коду). В результате остается корректным лишь последний добавленный обработчик.
Вопрос: как сказать компилятору, что бы он эту процедуру оптимизировал каким-либо подходящим образом для этого случая?

Автор: A1ukard 21.12.2008, 17:49
Лучше всего будет воздержаться от использования асма в программах на C++.
Ваша программа не будет компилироваться, если компилятор не знает синтаксиса AT&T. Также другой компилятор под другой платформой скорее всего также соберет программу неправильно (что-нибудь затрет в стеке). Использовать метки и goto тоже не рекомендуется.

В C++ есть миханизм обработки исключений. Для чего нужен finally, если программа так или иначе продолжит свое выполнение, покинув try-блок?


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

Автор: jonie 21.12.2008, 17:53
Цитата

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

Автор: victor79 21.12.2008, 17:58
у меня си, а не си++, и компилиться будет только под mingw, для одного проекта.
в си нету компиляции блоков try.

Автор: Lazin 21.12.2008, 19:57
вы сначала изобретаете исключения, затем эмулируете классы, затем RTTI, проще сразу использовать с++
поскольку используется mingw, речь идет о windows, а на этой платформе есть механизм SEH, логично использовать его

Автор: A1ukard 21.12.2008, 20:34
Ну в данной ассемблерной вставке именно SEH для перехвата исключений и используется.
MinGW, если память не изменяет, С++ тоже компилит, потому отчего бы не заюзать try?

Или напишите в MASM функцию, которая в качестве аргумента принимает указатель на callback процедуру. если происходит ошибка, функция возвращает отрицательное число, иначе - ноль.

получится что-то вроде

Код

if(catch_exception(&my_prog, &arg_struct)) {
  printf("поймана ошибка\n");
}

printf("а это - наш finally\n");

Автор: victor79 21.12.2008, 21:12
кстати в mingw есть библиотека excpt.h, где макросы __try1 и __except1 именно такой ошибочный способ и использую - создают EXCEPTION_REGISTRATION в стеке через push.

Автор: mes 21.12.2008, 21:21
victor79, может это поможет:
http://www.insidepro.com/kk/014/014r.shtml
http://www.securitylab.ru/contest/212085.php

Автор: victor79 21.12.2008, 21:44
to mes, я еще вчера хотел у вас на плюсик в репутации нажать, да меня обломало - меньше 100 сообщений)
за пару минут до вашего сообщения я вспомнил про функцию alloca - выделение памяти в стеке, а после в одной из ваших ссылок - что можно же просто объявить переменную вида int buf[4]. Теперь дополнив это еще вчерашней ссылкой про расширение C (http://linfoline.homedns.org/gcc27/gcc1-4.html) у меня есть весь необходимый инвентарь для создания собственного обработчика исключений. Как доделаю, выложу на обсуждение - вдруг кому-нибудь понадобиться. Спасибо.

Автор: Lazin 21.12.2008, 22:22
подобные механизмы обработки исключений, лично меня ломают, так как я пишу на с++, а это поломало бы там абсолютно все, но для си может и сработать... хотя все-же лучше использовать то что предостовляется компилятором, так как это будет переносимо, плюс это не только ты один будешь использовать. не знаю как насчет mingw, а сишный компилятор фирмы microsoft умеет исключения и знает __try и __finally, может лучше использовать его?

Автор: SABROG 22.12.2008, 00:30
Цитата(Lazin @  21.12.2008,  19:57 Найти цитируемый пост)
поскольку используется mingw, речь идет о windows, а на этой платформе есть механизм SEH, логично использовать его 


Имхо наоборот не логично, используют mingw обычно для кроссплатформенных проектов. В принципе и под линуксом mingw работает, т.е. собирает программы для windows. Но все-таки использование вставок asm'a это привязка к конкретному компилятору и конкретно к семейству процессоров.

Милая аватарка  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)