Соглашение о вызове cedecl - скомпилированные asm-инструкции вызывают сбой - PullRequest
1 голос
/ 22 января 2010

Относитесь к этому больше как к псевдокоду, чем к чему-либо. Если есть какой-то макрос или другой элемент, который, по вашему мнению, должен быть включен, дайте мне знать.

Я довольно новичок в сборке. Я программировал на фотопроцессоре еще в колледже, но с тех пор ничего.

Проблема здесь (ошибка сегментации) - первая инструкция после «Вход функции компиляции, кадр стека настройки». или "push% ebp". Вот что я узнал об этих двух инструкциях:

http://unixwiz.net/techtips/win32-callconv-asm.html

Сохраните и обновите% ebp:

Теперь, когда мы в новой функции, нам нужен новый фрейм локального стека, на который указывает% ebp, поэтому это делается путем сохранения текущего% ebp (который принадлежит фрейму предыдущей функции) и установки его в вершина стека.

    push ebp
    mov  ebp, esp    // ebp « esp

После изменения% ebp он теперь может напрямую ссылаться на аргументы функции как 8 (% ebp), 12 (% ebp). Обратите внимание, что 0 (% ebp) является старым указателем базы, а 4 (% ebp) является указателем старой инструкции.

Вот код. Это из JIT-компилятора для проекта, над которым я работаю. Я делаю это больше для обучения, чем для всего.

IL_CORE_COMPILE(avs_x86_compiler_compile)
{
    X86GlobalData *gd = X86_GLOBALDATA(ctx);
    ILInstruction *insn;

    avs_debug(print("X86: Compiling started..."));
    /* Initialize X86 Assembler opcode context */
    x86_context_init(&gd->ctx, 4096, 1024*1024);

    /* Compile function entrance, setup stack frame*/
    x86_emit1(&gd->ctx, pushl, ebp);
    x86_emit2(&gd->ctx, movl, esp, ebp);

    /* Setup floating point rounding mode to integer truncation */
    x86_emit2(&gd->ctx, subl, imm(8), esp);
    x86_emit1(&gd->ctx, fstcw, disp(0, esp));
    x86_emit2(&gd->ctx, movl, disp(0, esp), eax);
    x86_emit2(&gd->ctx, orl, imm(0xc00), eax);
    x86_emit2(&gd->ctx, movl, eax, disp(4, esp));
    x86_emit1(&gd->ctx, fldcw, disp(4, esp));

    for (insn=avs_il_tree_base(tree); insn != NULL; insn = insn->next) {
        avs_debug(print("X86: Compiling instruction: %p", insn));
        compile_opcode(gd, obj, insn);
    }

    /* Restore floating point rounding mode */
    x86_emit1(&gd->ctx, fldcw, disp(0, esp));
    x86_emit2(&gd->ctx, addl, imm(8), esp);

    /* Cleanup stack frame */
    x86_emit0(&gd->ctx, emms);
    x86_emit0(&gd->ctx, leave);
    x86_emit0(&gd->ctx, ret);

    /* Link machine */
    obj->run = (AvsRunnableExecuteCall) gd->ctx.buf;
    return 0;
}

И когда вызывается obj-> run, он вызывается с obj в качестве единственного аргумента:

obj->run(obj);

Если это поможет, вот инструкции для всего вызова функции. Это в основном операция присваивания: foo=3*0.2;. foo указывает на число с плавающей точкой в ​​C.

0x8067990:  push   %ebp 
0x8067991:  mov    %esp,%ebp
0x8067993:  sub    $0x8,%esp
0x8067999:  fnstcw (%esp)
0x806799c:  mov    (%esp),%eax
0x806799f:  or     $0xc00,%eax
0x80679a4:  mov    %eax,0x4(%esp)
0x80679a8:  fldcw  0x4(%esp)
0x80679ac:  flds   0x806793c
0x80679b2:  fsts   0x805f014
0x80679b8:  fstps  0x8067954
0x80679be:  fldcw  (%esp)
0x80679c1:  add    $0x8,%esp
0x80679c7:  emms   
0x80679c9:  leave  
0x80679ca:  ret    

Редактировать: Как я уже говорил выше, в первой инструкции этой функции% ebp void. Это также инструкция, которая вызывает ошибку сегментации. Это потому что оно пустое или я ищу что-то еще?

Редактировать: поцарапать это. Я продолжаю набирать edp вместо ebp. Вот значения ebp и esp.

(gdb) print $esp
$1 = (void *) 0xbffff14c
(gdb) print $ebp
$3 = (void *) 0xbffff168

Редактировать: Эти значения выше неверны. Я должен был использовать команду 'x', как показано ниже:

(gdb) x/x $ebp
0xbffff168: 0xbffff188
(gdb) x/x $esp
0xbffff14c: 0x0804e481

Вот ответ от кого-то из списка рассылки по этому поводу. Кто-нибудь хочет осветить, что он имеет в виду немного? Как проверить, как настроен стек?

Непосредственная проблема, которую я вижу, заключается в том, что указатель стека неправильно выровнен. Это 32-битный код, а Intel Руководство говорит, что стек должен быть выровнен по 32-битным адресам. То есть, наименее значимая цифра в esp должно быть 0, 4, 8 или c.

Также отмечу, что значения в ebp и ESP очень далеко друг от друга. Как правило, они содержат похожие значения - адреса где-то в стеке.

Я бы посмотрел, как был установлен стек в этой программе.

Он ответил с исправлениями к вышеприведенным комментариям. Он не смог увидеть никаких проблем после дальнейшего ввода.

Другое редактирование: кто-то ответил, что кодовая страница не может быть помечена как исполняемая. Как я могу гарантировать, что он помечен как таковой?

Ответы [ 2 ]

1 голос
/ 22 января 2010

Проблема не имеет ничего общего с кодом.Добавление -z execstack к компоновщику устранило проблему.

1 голос
/ 22 января 2010

Если push %ebp вызывает segfault, то ваш указатель стека не указывает на действительный стек. Как контроль достигает этой точки? На какой платформе вы работаете, и есть ли что-то странное в среде выполнения? При входе в функцию %esp должен указывать на адрес возврата в вызывающей стороне в стеке. Есть ли это?

Кроме того, вся функция довольно странная. Вы стараетесь установить биты округления в контрольном слове fp, а затем не выполняете никаких операций, на которые влияет округление. Все, что делает функция, это копирует некоторые данные, но использует регистры с плавающей запятой, чтобы сделать это, когда вы также можете использовать целочисленные регистры. И еще есть ложные emms, которые вам нужны после использования инструкций MMX, а не после выполнения вычислений x87.

Редактировать См. Ответ Скотта (первоначальный спрашивающий) о действительной причине аварии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...