Borland x86内联汇编程序;得到标签的地址?

时间:2008-10-16 15:59:41

标签: c++ assembly x86 turbo-c++

我正在使用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”。 / p>

有人可以建议如何让这个工作吗?

更新:要响应Pax的问题​​(请参阅注释),如果Windows加载程序在运行时更改了基址,则Windows加载程序仍将重定位DLL / EXE PE映像,并且将修补标签地址加载器运行时使用基于重新的地址,因此使用标签地址的编译/链接时间值不是问题。

非常感谢提前。

12 个答案:

答案 0 :(得分:4)

上次我试图制作一些与Borland兼容的汇编代码时,我遇到了你无法转发标签的限制。不确定这是不是你在这里遇到的。

答案 1 :(得分:4)

我能找到的关于Borland的一切建议都应该有效。其他网站(herehere)上的类似问题表明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:

&amp;&amp; operator是一个非标准扩展,我不希望它在gcc以外的任何地方工作。希望这可能会激起一些新的想法......祝你好运!

编辑:虽然它被列为Microsoft特定的,但here是另一个跳转到标签的实例。

答案 2 :(得分:1)

3条建议:

1)在程序集中的SomeLabel前放一个'_',使它成为“mov eax,_SomeLabel “。通常,编译器在将C转换为汇编时会添加一个。

或者

2)将标签放在装配部分。这将阻止编译器添加“_”。

或者

3)注释掉程序集,编译并查看列表文件(* .lst)以查看标签名称变为什么。

答案 3 :(得分:1)

Turbo C ++环境是否有办法为TASM设置选项(我知道一些Borland IDE的确如此)?

如果是这样,请查看将“最大通过次数(/ m)”更改为2或更多是否有帮助(可能默认为1次通过)。

此外,如果您使用可能造成问题的长标签名称 - 至少有一个IDE将默认设置为12.更改“最大符号长度(/ mv)选项”。

此信息基于Borland的RAD Studio IDE:

答案 4 :(得分:1)

尝试更多的事情(在黑暗中拍摄):

  • 查看使用以下汇编指令是否有帮助:

    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;
    }
    

    查看程序集列表,看看生成的程序集是否能够以内联程序集中的方式复制标签名称。

答案 5 :(得分:0)

根据我的记忆,您不能在内联汇编中使用外部(C ++)标签,尽管您可以在asm块中使用TASM样式的标签,这些标签可以由汇编指令本身引用。我想我会使用一个标志和一个post-assembler switch语句来处理分支。例如:

int result=0;

__asm__ {
    mov result, 1
}

switch (result){
    case 1:  printf("You wanted case 1 to happen in your assembler\n"); break;
    case 0:  printf("Nothing changed with the result variable.. defaulting to:\n");
    default: printf("Default case!\n"); break;
}

答案 6 :(得分:0)

我不知道你的编译器/汇编程序,但我使用的一个技巧是调用下一个位置然后将堆栈弹出到你的寄存器中。确保您拨打的电话只会推送返回地址。

答案 7 :(得分:0)

我认为你遇到的问题是__asm块内的标签和C ++代码中的标签是两个完全不同的东西。我不希望你能从内联汇编中以这种方式引用C ++标签,但我必须说自从我使用Turbo C ++以来已经很长时间了。

您是否尝试过lea指令而不是mov

答案 8 :(得分:0)

这是一种可能的方法:

// 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;
}

它有点hacky但它​​适用于我拥有的Turbo C ++版本。它几乎肯定取决于编译器和优化设置。

答案 9 :(得分:0)

因为我没有在任何C / ++编译器中使用内联汇编程序而只是猜测......

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

我不知道TASM的确切语法。

答案 10 :(得分:0)

这是伊万建议的变体,但试试看:

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

答案 11 :(得分:0)

其中一个选项是使用单独的“裸”(无序)程序SomeLabel而不是标签