Borland x86 inlined assembler; get a label's address?

前端 未结 12 863
清酒与你
清酒与你 2021-01-05 03:15

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         


        
相关标签:
12条回答
  • 2021-01-05 03:38

    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.

    0 讨论(0)
  • 2021-01-05 03:39

    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.

    0 讨论(0)
  • 2021-01-05 03:42

    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.

    0 讨论(0)
  • 2021-01-05 03:45

    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.

    0 讨论(0)
  • 2021-01-05 03:45

    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.

    0 讨论(0)
  • 2021-01-05 03:49

    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;
    }
    
    0 讨论(0)
提交回复
热议问题