Borland x86 встроенный ассемблер; получить адрес этикетки? - PullRequest
8 голосов
/ 16 октября 2008

Я использую Borland Turbo C ++ с некоторым встроенным ассемблерным кодом, так что, вероятно, ассемблерный код в стиле Turbo Assembler (TASM). Я хочу сделать следующее:

void foo::bar( void )
{
    __asm
    {
      mov eax, SomeLabel
      // ...
    }
    // ...
SomeLabel:
    // ...
}

Таким образом, адрес SomeLabel помещается в EAX. Это не работает, и компилятор жалуется на: неопределенный символ 'SomeLabel'.

В Microsoft Assembler (MASM) символ доллара ($) служит текущим счетчиком местоположения, что было бы полезно для моей цели. Но, опять же, это не работает в Borlands Assember (синтаксическая ошибка выражения).

Обновление: чтобы быть более конкретным, мне нужен компилятор для генерации адреса, который он перемещает в eax как константу во время компиляции / компоновки, а не во время выполнения, поэтому он будет компилироваться как "mov eax, 0x00401234".

Кто-нибудь может подсказать, как заставить это работать?

ОБНОВЛЕНИЕ: Чтобы ответить на вопрос Пакса (см. Комментарий), если базовый адрес изменяется во время выполнения загрузчиком Windows, образ DLL / EXE PE по-прежнему будет перемещаться загрузчиком Windows, а адрес меток будет исправлен в время выполнения загрузчиком для использования переопределенного адреса, поэтому использование значения времени компиляции / ссылки для адреса метки не является проблемой.

Большое спасибо заранее.

Ответы [ 12 ]

4 голосов
/ 28 января 2009

Все, что я могу найти о Borland, предполагает, что это должно сработать. Подобные вопросы на других сайтах ( здесь и здесь ) предполагают, что Borland может обрабатывать прямые ссылки на метки, но настаивает на том, чтобы метки находились вне блоков asm. Однако, поскольку ваша метка уже была вне блока asm ...

Мне любопытно, позволит ли ваш компилятор использовать эту метку, например, в инструкции jmp. Работая с ним (по общему признанию, на совершенно другом компиляторе), я обнаружил досадную склонность компилятора жаловаться на типы операндов.

Синтаксис совсем другой, и это моя первая попытка inline asm за долгое время, но я считаю, что я сделал это достаточно для работы под gcc. Возможно, несмотря на различия, это может быть полезным для вас:

#include <stdio.h>
int main()
{
    void *too = &&SomeLabel;
    unsigned int out;
    asm
    (
      "movl %0, %%eax;"
      :"=a"(out)
      :"r"(&&SomeLabel)
    );
SomeLabel:
    printf("Result: %p %x\n", too, out);

    return 0;
}

Создает:

...
        movl    $.L2, %eax
...
.L2:

Оператор && является нестандартным расширением, я не ожидал бы, что он будет работать где-либо, кроме gcc. Надеюсь, это могло вызвать новые идеи ... Удачи!

Редактировать: Хотя он указан как специфичный для Microsoft, здесь является еще одним примером перехода к меткам.

4 голосов
/ 17 октября 2008

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

1 голос
/ 03 февраля 2009

Еще пара вещей (выстрелы в темноте), чтобы попробовать:

  • посмотрите, поможет ли использование следующей инструкции по сборке:

    mov eax, offset SomeLabel
    
  • большинство компиляторов могут создать список сборки кода, который они генерируют (не уверен, что Turbo C ++ может, так как Codegear / Embarcadero позиционирует его как бесплатный непрофессиональный компилятор).

    Попробуйте создать листинг с кодом C, в котором используется метка (например, цель goto) с некоторой встроенной сборкой в ​​той же функции, но не пытайтесь получить доступ к метке из сборки. Это позволяет получить компилятор без ошибок и список сборок. Что-то вроде:

    int foo()
    {
        int x = 3;
        printf( "x =%d\n", x);
        goto SomeLabel;
                               //
        __asm {
            mov eax, 0x01
        }
                               //
    SomeLabel:
        printf( "x =%d\n", x);
                               //
        return x;
    }
    

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

1 голос
/ 03 февраля 2009

Есть ли в среде Turbo C ++ способ установки параметров для TASM (я знаю, что некоторые из IDE Borland сделали это)?

Если это так, посмотрите, если изменить параметр «Максимальное количество проходов (/ м)» на 2 или более подсказок (по умолчанию это может быть 1 проход).

Кроме того, если вы используете длинное имя метки, которое может вызвать проблемы - по крайней мере для одной IDE по умолчанию установлено значение 12. Измените параметр «Максимальная длина символа (/ mv)».

Эта информация основана на IDE Borland RAD Studio:

1 голос
/ 16 октября 2008

3 предложения:

1) поместите '_' перед SomeLabel в сборке, чтобы он стал "mov eax, _SomeLabel" Msgstr "Обычно компилятор добавляет его, когда переводит C в сборку.

Или

2) положить этикетку в сборочный раздел. Это предотвратит добавление компилятором '_'.

Или

3) закомментируйте сборку, скомпилируйте и посмотрите в файле листинга (* .lst), чтобы увидеть, каким будет имя метки.

0 голосов
/ 10 октября 2013

одним из вариантов будет использование отдельной «голой» (без прологов) процедуры SomeLabel вместо метки

0 голосов
/ 13 ноября 2010

Это вариант предложения Ивана, но попробуйте:

void foo::bar( void )
{
    __asm
    {
      mov eax, offset SomeLabel
      // ...
    }
    // ...
    __asm SomeLabel:
    // ...
}
0 голосов
/ 28 января 2009

Просто догадываюсь, так как я не использовал встроенный ассемблер с любым компилятором C / ++ ...

void foo::bar( void )
{
    __asm
    {
      mov eax, SomeLabel
      // ...
    }
    // ...
    __asm
    {
      SomeLabel:
      // ...
    }
    // ...
}

Я не знаю точный синтаксис TASM.

0 голосов
/ 27 января 2009

Вот возможный метод:

// get_address
// gets the address of the instruction following the call
// to this function, for example
//     int addr = get_address (); // effectively returns the address of 'label'
//   label:
int get_address ()
{
    int address;
    asm
    {
        mov eax,[esp+8]
        mov address,eax
    }
    return address;
}
// get_label_address
// a bit like get_address but returns the address of the instruction pointed
// to by the jmp instruction after the call to this function, for example:
//     int addr;
//     asm
//     {
//       call get_label_address // gets the address of 'label'
//       jmp label
//       mov addr,eax
//     }
//     <some code>
//   label:
// note that the function should only be called from within an asm block.
int get_label_address()
{
    int address = 0;
    asm
    {
        mov esi,[esp+12]
        mov al,[esi]
        cmp al,0ebh
        jne not_short
        movsx eax,byte ptr [esi+1]
        lea eax,[eax+esi-1]
        mov address,eax
        add esi,2
        mov [esp+12],esi
        jmp done
    not_short:
        cmp al,0e9h
        jne not_long
        mov eax,dword ptr [esi+1]
        lea eax,[eax+esi+2]
        mov address,eax
        add esi,5
        mov [esp+12],esi
        jmp done
    not_long:
        // handle other jmp forms or generate an error
    done:
    }
    return address;
}
int main(int argc, char* argv[])
{
    int addr1,addr2;
    asm
    {
        call get_label_address
        jmp Label1
        mov addr1,eax
    }

    addr2 = get_address ();
Label1:
    return 0;
}

Это немного странно, но работает в той версии Turbo C ++, которая у меня есть. Это почти наверняка зависит от компилятора и настроек оптимизации.

0 голосов
/ 27 января 2009

Я думаю, что проблема, с которой вы сталкиваетесь, заключается в том, что метка внутри блока __asm и метка в коде C ++ - это две совершенно разные вещи. Я бы не ожидал, что вы можете ссылаться на метку C ++ таким образом из встроенной сборки, но я должен сказать, что прошло очень много времени с тех пор, как я использовал Turbo C ++.

Вы пробовали инструкцию lea вместо mov?

...