3

Consider this code:

#include <cstdio>

int get_value() { asm("movl $254, %eax"); }

int main() { printf("%d\n", get_value()); }

Now if one compiles this code with g++ main.cpp, one gets a compiler warning (but the code still compiles):

main.cpp: In function ‘int get_value()’:
main.cpp:3:43: warning: no return statement in function returning non-void [-Wreturn-type]
    3 | int get_value() { asm("movl $254, %eax"); }
      |                                    

As this answer says that if a compiler generates a binary with the above code, all bets are off. (no return statement from a function with return type int)

Indeed, when one compiles this code with optimization turned on g++ -O3 main.cpp, this program immediately segfaults.

So my question is how can one return from inline assembly within a c++ function that is conformant with C++, and one doesn't get this warning, and the code works fine.

Michael Chourdakis
  • 10,345
  • 3
  • 42
  • 78
skgbanga
  • 2,477
  • 2
  • 20
  • 29
  • 1
    If you want machine code go with C, C++ is designed to be working on abstract machine. So after compiling these with C then you can import these methods into C++ using extern "C". If you will ignore the fact what C++ is for and go with non-standard then play with calling conventions cdecl should be what you are looking for https://stackoverflow.com/questions/10463960/inline-assembly-cdecl-and-preparing-the-stack – Abdurrahim Jan 15 '20 at 15:44
  • You can't just fall off the end of a non-`void` function (only MSVC's clunky / bad `_asm{}` allows that as a hack). Of course this breaks when GCC inlines your function. Also, don't lie to the compiler: you destroy EAX without telling it. See https://stackoverflow.com/tags/inline-assembly/info for tutorials. – Peter Cordes Jan 15 '20 at 23:52

1 Answers1

4

I believe what you have to do is declare a dummy variable, and use the gcc extended syntax to output that variable, and then you can return that variable. The optimiser should strip both assignents out.

It is sort-of explained in https://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html#s5, and might look like this:

#include <cstdio>

int get_value() {
  int b;
  asm("movl $254, %0;"
      : "=r"(b)
      );
  return b;
}

int main() {
  printf("%d\n", get_value());
}
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Gem Taylor
  • 5,381
  • 1
  • 9
  • 27
  • That explains it. Would you mind editing your answer to include the correct code. https://coliru.stacked-crooked.com/a/db7725efca004d52. Thanks. – skgbanga Jan 15 '20 at 16:04
  • If you're using an extended syntax, is it C++ compliant or GCC specific? –  Jan 15 '20 at 16:11
  • 2
    @Chipster It is not. As this page says: https://en.cppreference.com/w/cpp/language/asm, all compilers have different conventions for different platforms. For my case, I was looking to make it work with gcc and linux, and this worked. I think this is "implementation defined" and not "undefined behaviour" as my original code was. – skgbanga Jan 15 '20 at 16:14
  • Ah, okay. That makes sense. –  Jan 15 '20 at 16:15
  • Thanks to "Lightness Races BY-SA 3.0" for the example.I was just quoting the docs, and don't have a good example to hand. – Gem Taylor Jan 15 '20 at 17:29