views:

2096

answers:

10

Hello

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.

+1  A: 

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.

Robert
Thanks, good suggestions but unfortunately #1 and #2 dont work. I'll try testing #3 a little more, but no luck so far.
QAZ
A: 

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;
}
Sean
I have tryed the label inside the asm block and it doesnt help. Unfortunatly I need it to work as per the example so appending a switch statement is no use. Thanks though.
QAZ
A: 

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.

piCookie
good suggestion. I've used that trick for many other things in the security field. For this though I specifically need the compiler to assemble the address as a constant at compile time and not run time. thanks for your suggestion though.
QAZ
+3  A: 

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.

Adam Mitz
A: 

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?

Greg Hewgill
Hi Greg, Yes I tried LEA also but no joy.
QAZ
A: 

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.

Skizz

Skizz
The get_label_address function modifies its return address so the jmp that follows the call isn't executed.
Skizz
A: 

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.

Ivan Vučica
Thanks ivucica but unfortunately it doesn't work.
QAZ
+2  A: 

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.

Kim Reece
QAZ
+1  A: 

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:

Michael Burr
Hi Michael, good idea about setting the maximum passes, just tried and no joy but ill try tweaking it some more
QAZ
Does it work for labels that occur before the __asm block?
Michael Burr
Also I know some assemblers use a hint to indicate a label is a forward reference. I don't think TASM was one of them, but it's worth a try: use "mov eax, >SomeLabel" - the '>' character is the hint to the assembler.
Michael Burr
negative for labels that occur before the asm block. I managed to crash the compiler by pre pending an @ symbol to the label! :)
QAZ
A: 

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.

Michael Burr