0

I try to understand how the extended inline assembly in GCC works. But when I try to run a simple test program I get the error: "invalid instruction suffix for mov"

The sample program:

unsigned char destination;
unsigned char ret;
unsigned int somevalue;

asm ("movb %1, %%al\n\t"
    "push %1\n\t"
    "pop edx\n\t"
    "not %%al\n\t"
    "movb %%al, %0"
    : "=r" (destination), "=r"(somevalue)
    : "r" (ret));

destination shall be loaded into al. After that somevalue is pushed onto the stack. After that it is pop'd in the edx register. The not instruction shall be performed on al which contains the value of destination. After that the result shall be given out to ret. There is no restriction which registers to use to perform this program (I guess that means all registers as clobbers?).

MenNotAtWork
  • 125
  • 6
  • 1
    Look at the compiler-generated asm output (e.g. on https://godbolt.org/) to see how GCC fills in the asm template. `%1` will be a 32-bit register (because `unsigned int`). So `movb %ecx, %al` obviously can't work because the operands are different sizes. Perhaps you want `%b1` to print the byte version of that reg name? You're reading an `"=r"` output-only operand so IDK what you want this to do. **And it's impossible to make this usable because you leave the asm with ESP/RSP modified by `push` - there's no way to tell GCC about this.** Also you forgot to declare an EAX clobber – Peter Cordes Mar 14 '20 at 05:51
  • Are you sure you're using GCC and not clang (e.g. on MacOS which installs clang as `gcc`)? If you're using an option for Intel-syntax assembly then clang's assembler won't accept `movb` only `mov`. – Peter Cordes Mar 14 '20 at 05:53
  • @PeterCordes Yes I'm using GCC. The standard compiler you get when you install Code::Blocks (the IDE I use). I'm using it on a Windows 8.1 VM. – MenNotAtWork Mar 14 '20 at 15:08
  • @PeterCordes I have to admit that I do not really understand the inline assembly yet. The push instruction was just put in because I need to know how the inline assembly works, when I have 2 input variables. The program is just a slightly altered copy of the sample program from the [documentary](https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html). That's where the "=r" comes from. – MenNotAtWork Mar 14 '20 at 15:13
  • @PeterCordes The most helpful thing would be if you could give me a functional sample program in inline assembly that would do what I wrote as a description under the code chunk. So I understand what exactly is wrong with my code. (I altered the code chunk and the description). – MenNotAtWork Mar 14 '20 at 15:20
  • It's meaningless to read from an output-only operand, and `%1` is `someval` not `destination`. You should generally avoid push/pop in inline asm. What plain C function are you trying to implement with asm? Are you trying to do `destination = ret = ~someval;`? – Peter Cordes Mar 14 '20 at 18:19
  • 1
    It is (generally) a mistake to specify which registers to use: eg the `%%al` and `edx` (I assume you meant `%%edx`) you use. See [my answer](https://stackoverflow.com/questions/60237447) to another question. If you do need specific registers for particular instructions, it is better to use the right "operand constraint" -- for `EAX` as an output you would specify `=a (foo)`. Otherwise, if you must use (say) `EBX`, you **must** tell the compiler by specifying a "clobber". By the way, you can write one instruction per `__asm__()` statement, which may make it easier to see what's going on. – Chris Hall Mar 14 '20 at 18:21
  • 2
    As @PeterCordes says, the problem with the `movb %1, %%al` is that `%1` refers to `"=r"(somevalue)`: (leaving to one side the fact that the `=` means that this is an _output_) the `r` says this is a register and the `%1` will expand to whatever 32-bit register gcc has allocated for `somevalue` to be read into -- the result is (say) `movb %%ecx, %%al`, which ain't valid. The one of the "x86 Operand Modifiers" will do the trick, thus `movb %b1, %%al` will ask for the (ls) byte of the register allocated for `somevalue`. – Chris Hall Mar 14 '20 at 18:21
  • Ok, I changed my code again. I used `=a`, `=b` etc. to work with the registers. My program now seems to work: `asm("push %%ebx\n\t" "pop %%edx\n\t" "not %%al\n\t" : "=a" (ret) : "a" (destination), "b"(somevalue) );` – MenNotAtWork Mar 14 '20 at 19:33

0 Answers0