문제

나는 일부 인라인 어셈블러 코드와 함께 Borland Turbo C ++를 사용하고 있습니다. 다음을하고 싶습니다.

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

따라서 Somelabel의 주소는 EAX에 배치됩니다. 이것은 작동하지 않으며 컴파일러는 다음과 같이 불만을 제기합니다.

Microsoft Assembler (MASM)에서 달러 기호 ($)는 현재 위치 카운터 역할을하며 이는 내 목적에 유용합니다. 그러나 다시 이것은 Borlands Assemb (Expression Syntax 오류)에서 작동하지 않는 것 같습니다.

업데이트 : 좀 더 구체적으로 보려면 컴파일/링크 중에 eAx로 이동하는 주소를 생성하려면 컴파일러가 필요하지 않으며 런타임이 아닌 컴파일/링크 중에 상수로 이동해야하므로 "Mov EAX, 0x00401234"와 같이 컴파일됩니다.

누구 든지이 작업을 수행하는 방법을 제안 할 수 있습니까?

업데이트 : PAX의 질문에 응답하려면 (주석 참조), Windows 로더가 실행 시간에 기본 주소가 변경되면 DLL/EXE PE 이미지는 여전히 Windows 로더에 의해 재배치되고 레이블 주소는 실행 시간에 패치됩니다. 라벨 주소의 Compile/Link 시간 값을 사용하는 RE 기반 주소를 사용하는 로더는 문제가되지 않습니다.

미리 감사드립니다.

도움이 되었습니까?

해결책

지난번에 어셈블리 코드 Borland 호환을 만들려고했을 때 나는 당신이 라벨을 전달할 수 없다는 제한을 발견했습니다. 그것이 당신이 여기서 달리는 것인지 확실하지 않습니다.

다른 팁

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.

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.

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:

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.

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

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.

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?

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.

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

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

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.

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

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top