首页 文章

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

提问于
浏览
8

我正在使用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” .

任何人都可以建议如何使这个工作?

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

提前谢谢了 .

12 回答

  • 0

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

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

    我不知道TASM的确切语法 .

  • 0

    这是Ivan建议的变体,但尝试一下:

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

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

  • 1

    我能找到的关于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:
    

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

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

  • 1

    3意见建议:

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

    要么

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

    要么

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

  • 0

    Turbo C环境是否有办法为TASM设置选项(我知道一些Borland IDE可以做到)?

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

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

    此信息基于Borland的RAD Studio IDE:

  • 4

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

    • 看看使用以下汇编指令是否有帮助:
    mov eax, offset SomeLabel
    
    • 大多数编译器可以生成他们生成的代码的汇编列表(不确定Turbo C是否可以,因为Codegear / Embarcadero将其定位为免费的非专业编译器) .

    尝试生成一个包含C代码的列表,该代码使用标签(例如 goto target),在同一函数中使用一些内联汇编 - 但不要尝试从汇编中访问标签 . 这样您就可以获得没有错误的编译器和汇编列表 . 就像是:

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

    查看程序集列表,查看生成的程序集是否以您可能能够在内联程序集中进行复制的方式修饰标签名称 .

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

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

  • 0

    我认为你遇到的问题是 __asm 块内的标签和C代码中的标签是两个完全不同的东西 . 自从我使用Turbo C以来,我已经很久没有了 .

    你试过 lea 指令而不是 mov 吗?

  • 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版本 . 它几乎肯定取决于编译器和优化设置 .

  • 1

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

相关问题