Borland x86 内联汇编器; 获取标签地址?

发布于 2024-07-08 11:27:07 字数 697 浏览 7 评论 0 原文

我使用 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 加载程序在运行时更改基址,则 DLL/EXE PE 映像仍将由 Windows 加载程序重新定位,并且标签地址将在运行时通过以下方式进行修补加载器使用重新基地址,因此使用标签地址的编译/链接时间值不是问题。

提前谢谢了。

I am using Borland Turbo C++ with some inlined assembler code, so presumably Turbo Assembler (TASM) style assembly code. I wish to do the following:

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

So the address of SomeLabel is placed into EAX. This doesn't work and the compiler complains of: Undefined symbol 'SomeLabel'.

In Microsoft Assembler (MASM) the dollar symbol ($) serves as the current location counter, which would be useful for my purpose. But again this does not seem to work in Borlands Assember (expression syntax error).

Update: To be a little more specific, I need the compiler to generate the address it moves into eax as a constant during compilation/linking and not at run time, so it will compile like "mov eax, 0x00401234".

Can anybody suggest how to get this working?

UPDATE: To respond to Pax's question (see comment), If the base address is changed at run time by the Windows loader the DLL/EXE PE image will still be relocated by the Windows loader and the labels address will be patched at run time by the loader to use the re-based address so using a compile/link time value for the label address is not an issue.

Many thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

著墨染雨君画夕 2024-07-15 11:27:07

上次我尝试使一些汇编代码与 Borland 兼容时,我遇到了不能前向引用标签的限制。 不确定这是否是您在这里遇到的情况。

Last time I tried to make some assembly code Borland-compatible I came across the limitation that you can't forward-reference labels. Not sure if that's what you're running into here.

汐鸠 2024-07-15 11:27:07

我能找到的关于 Borland 的一切都表明这应该可行。 其他网站上的类似问题(此处此处)建议 Borland 可以处理标签的前向引用,但是坚持标签位于 asm 块之外。 但是,由于您的标签已经在 asm 块之外...

我很好奇您的编译器是否允许您在 jmp 指令等内使用此标签。 当摆弄它时(诚然,在完全不同的编译器上),我发现编译器有抱怨操作数类型的讨厌倾向。

语法完全不同,这是我很长一段时间以来第一次尝试内联汇编,但我相信我已经对此进行了足够的修改,可以在 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 特定的,这里是另一个实例跳转到标签。

Everything I can find about Borland suggests this ought to work. Similar questions on other sites (here and here) suggest that Borland can handle forward-references for labels, but insists on labels being outside asm blocks. However, as your label was already outside the asm block...

I am curious whether your compiler would allow you to use this label within, for instance, a jmp instruction. When toying around with it (admittedly, on a completely different compiler), I found a pesky tendency for the compiler to complain about operand types.

The syntax is quite different, and it's my first attempt at inline asm in a long time, but I believe I've munged this enough to work under gcc. Perhaps, despite the differences, this might be of some use to you:

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

This generates:

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

The && operator is a non-standard extension, I wouldn't expect it to work anywhere other than gcc. Hopefully this may have stirred up some new ideas... Good luck!

Edit: Though it's listed as Microsoft specific, here is another instance of jumping to labels.

小情绪 2024-07-15 11:27:07

3个建议:

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

或者

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

或者

3)注释掉汇编,编译并查看在列表文件 (*.lst) 中查看标签名称变成了什么。

3 suggestions:

1) put a '_' in front of the SomeLabel in the assembly so it becomes "mov eax, _SomeLabel
". Usually the compiler will add one when it translates C into assembly.

Or

2) put the label in an assembly section. This will prevent the compiler from adding the '_'.

Or

3) comment out the assembly, compile, and look in the listing file (*.lst) to see what the label name becomes.

素衣风尘叹 2024-07-15 11:27:07

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

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

I think the problem you're running into is that a label inside the __asm block and the label in the C++ code are two completely different things. I wouldn't expect that you could reference a C++ label in that way from inline assembly, but I must say it's been a very long time since I've used Turbo C++.

Have you tried the lea instruction instead of mov?

山色无中 2024-07-15 11:27:07

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

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

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

此信息基于 Borland 的 RAD Studio IDE:

Does the Turbo C++ environment have a way to set options for TASM (I know that some of the Borland IDEs did)?

If so, see if changing the option for "Maximum passes (/m)" to 2 or more helps (it might default to 1 pass).

Also, if you're using a long label name that might pose a problem - at least one IDE had the default set to 12. Change the "Maximum symbol length (/mv) option".

This information is based on Borland's RAD Studio IDE:

谁对谁错谁最难过 2024-07-15 11:27:07

还有一些事情(在黑暗中拍摄)可以尝试:

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

    mov eax, offset SomeLabel 
      
  • 大多数编译器都可以生成它们生成的代码的汇编列表(不确定 Turbo C++ 是否可以,因为 Codegear/Embarcadero 将其定位为免费的、非专业编译器)。

    尝试使用具有标签(例如作为 goto 目标)的 C 代码生成一个列表,并在同一函数中使用一些内联汇编 - 但不要尝试访问该标签从大会。 这样您就可以获得没有错误的编译器和程序集列表。 类似于:

    int foo() 
      { 
          整数x=3; 
          printf("x =%d\n", x); 
          转到某个标签; 
                                 // 
          __asm { 
              移动eax,0x01 
          } 
                                 // 
      一些标签: 
          printf("x =%d\n", x); 
                                 // 
          返回x; 
      } 
      

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

A couple more things (shots in the dark) to try:

  • see if using the following assembly instruction helps:

    mov eax, offset SomeLabel
    
  • most compilers can produce an assembly listing of the code they generate (not sure if Turbo C++ can, since Codegear/Embarcadero position it as a free, non-professional compiler).

    Try producing a listing with C code that has an uses a label (as a goto target for example), with some inline assembly in the same function - but don't try to access the label from the assembly. This is so you can get a compiler with no errors and an assembly listing. Something like:

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

    Look at the assembly listing and see if the generated assembly decorates the label name in a way that you might be able to replicate in the inline assembly.

因为看清所以看轻 2024-07-15 11:27:07

据我所知,您不能在内联汇编中使用外部(C++)标签,尽管您可以在 asm 块中使用可以由汇编指令本身引用的 TASM 样式标签。 我想我会使用一个标志和一个后汇编器 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;
}

From what I recall, you can't use an external (C++) label in your inline assembly, although you can have TASM-style labels in the asm block that can be referenced by the assembly instructions itself. I think I would use a flag and a post-assembler switch statement to handle branching. For example:

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;
}
遥远的她 2024-07-15 11:27:07

我具体不了解您的编译器/汇编器,但我经常使用的一个技巧是调用下一个位置,然后将堆栈弹出到您的寄存器中。 确保您拨打的电话仅推送返回地址。

I don't know about your compiler / assembler specifically, but a trick I've used quite a bit is to call the next location and then pop the stack into your register. Be certain the call you make only pushes the return address.

独自←快乐 2024-07-15 11:27:07

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

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

我不知道 TASM 的确切语法。

Just guessing since I haven't used inline assembler with any C/++ compiler...

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

I don't know the exact syntax of TASM.

别念他 2024-07-15 11:27:07

这是伊万建议的一个变体,但请尝试一下:

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

This is a variant of Ivan's suggestion but give this a try:

void foo::bar( void )
{
    __asm
    {
      mov eax, offset SomeLabel
      // ...
    }
    // ...
    __asm SomeLabel:
    // ...
}
乖乖兔^ω^ 2024-07-15 11:27:07

这是一个可能的方法:

// 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++ 版本中工作。 几乎可以肯定,它取决于编译器和优化设置。

Here's a possible method:

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

It's a bit hacky but it works in the version of Turbo C++ that I have. It almost certainly is dependant on the compiler and optimisation settings.

女皇必胜 2024-07-15 11:27:07

选择之一是使用单独的“裸”(无序言)过程 SomeLabel 而不是标签

one of the options would be to use separate "naked" (prolog-less) procedure SomeLabel instead of label

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文