简体   繁体   中英

Using AT&T inline assembler for GCC

I'm writing a simple but a little specific program:

calculate number from it's factorial 根据阶乘计算数字
all calculations must be done on gcc inline asm (at&t syntax) 所有计算都必须在gcc内联asm上完成(at&t语法)

Source code:

#include <iostream>

int main()
{
        unsigned n = 0, f = 0;

        std::cin >> n;

        asm
        (
                "mov %0, %%eax \n"
                "mov %%eax, %%ecx \n"
                "mov 1, %%ebx \n"
                "mov 1, %%eax \n"
                "jmp cycle_start\n"
                "cycle:\n"
                "inc %%ebx\n"
                "mul %%ebx\n"
                "cycle_start:\n"
                "cmp %%ecx, %%eax\n"
                "jnz cycle\n"
                "mov %%ebx, %1 \n":

                "=r" (n):
                 "r" (f)

       );

       std::cout << f;

       return 0;
}

This code causes SIGSEV.

Identic program on intel asm syntax ( http://pastebin.com/2EqJmGAV ) works fine. Why my "AT&T program" fails and how can i fix it?

#include <iostream>

int main()
{
   unsigned n = 0, f = 0;

   std::cin >> n;

   __asm
   {
      mov eax, n

      mov ecx, eax
      mov eax, 1
      mov ebx, 1
      jmp cycle_start

      cycle:

      inc ebx
      mul ebx

      cycle_start:

      cmp eax, ecx
      jnz cycle

      mov f, ebx
   };
   std::cout << f;

   return 0;
}

UPD: Pushing to stack and restoring back used registers gives the same result: SIGSEV

You have your input and output the wrong way around.

So, start by altering

            "=r" (n):
             "r" (f)

to:

             "=r" (f) :
             "r" (n)

Then I suspect you'll want to tell the compiler about clobbers (registers you are using that aren't inputs or outputs):

So add:

  : "eax", "ebx", "ecx" 

after the two lines above.

I personally would make some other changes:

  1. Use local labels ( 1: and 2: etc), which allows the code to be duplicated without "duplicate label".
  2. Use %1 instead of %%ebx - that way, you are not using an extra register.
  3. Move %0 directly to %%ecx . You are loading 1 into %%eax two instructions later, so what purpose has it got to do in %%eax ?

[Now, I'ver written too much, and someone else has answered first... ]

Edit: And, as Anton points out, you need $1 to load the constant 1, 1 means read from address 1, which doesn't work well, and most likely is the cause of your problems

Hopefully there are no requirements to use nothing but gcc inline asm to figure it out. You can translate your AT&T example with nasm , then disassemble with objdump and see what's the right syntax.

I seem to recall that mov 1,%eax should be mov $1,%eax if you mean literal constant and not a memory reference.

An answer by @MatsPetersson is very useful regarding the interaction of your inline assembly with the compiler (clobbered/input/output registers). I've focused on the reason why you get SIGSEGV , and reading the address 1 does answer the question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM