-1

First of all... I am a total noob with assembly. I understand almost nothing. But this code which you are gonna see below works fine in Visual Studio. I just need to compile this to .o file using a simple g++ command.

g++ -o fileName.o filename.cpp

I need to translate assembly code written inside brackets {} to assembly written inside parentheses (). When I am trying to compile below code it crashes. Compiler suggest to use ( instead of {

unsigned char decode5a[0x0dac];
unsigned char* srcbuf = new unsigned char[4000];
m_image = new unsigned char[4000];
unsigned char* dstbuf = m_image;

__asm
{
     lea eax, decode5a
     push srcbuf
     push dstbuf
     call eax
     add esp, 8
}

I tried something like that but it crash also. I think I am passing variable incorrectly.

__asm__(
     "lea eax, decode5a \n
     push srcbuf \n
     push dstbuf \n
     call eax \n
     add esp, 8 \n
");
fuz
  • 88,405
  • 25
  • 200
  • 352
  • 1
    C or C++? C++ has standardized inline asm. C does not. – Lundin Dec 05 '22 at 10:47
  • I would prefer C++ – BiggestUbuntuNoobie Dec 05 '22 at 10:50
  • 2
    Try `((void (*)(char *, char *))decode5a)(srcbuf, dstbuf)`. No need to use inline assembly here. – fuz Dec 05 '22 at 10:53
  • @fuz could you tell me exactly how I should to append this to my code? I have no idea what this code does :/ – BiggestUbuntuNoobie Dec 05 '22 at 11:03
  • The reason the compiler suggests `(` instead of `{` has **nothing to do with** the "converting" the assembly. The problem is that the compiler expects `__asm` to be the **name of a function**, not a special construct for inline assembly - because it needs to be `__asm__` instead. – Karl Knechtel Dec 05 '22 at 11:03
  • @KarlKnechtel yeah I thought so. But I have no idea how to write this using `__asm__` – BiggestUbuntuNoobie Dec 05 '22 at 11:05
  • 2
    "could you tell me exactly how I should to append this to my code?" You should use it to **replace the inline assembly completely**. It does what you apparently intend for the assembly to do, but in C++. – Karl Knechtel Dec 05 '22 at 11:05
  • "yeah I thought so. But I have no idea how to write this using `__asm__`" Okay; but please keep in mind that Stack Overflow is **not a discussion forum** and we expect posts to be about **one** question. If you have already learned the the `__asm__` syntax and now there is a question about *making that version of the code work* (i.e. fixing the crash at runtime when the assembly code runs), and that is the question you want to ask here - then this is **no longer** a question about the syntax error involved in declaring inline ASM in the first place, and that should be [edit]ed out. – Karl Knechtel Dec 05 '22 at 11:08
  • But ideally, you are expected to determine which question you want to ask ahead of time, and stick to it - the point here is to create a **question** that helps build a library, **not** to make the code in your project work. Please review [ask] and the [tour]. – Karl Knechtel Dec 05 '22 at 11:09
  • @KarlKnechtel I tried to "ask ahead of time" as much as possible... My knowledge about assembly is poor but still I posted code from my attempt to solve the problem. – BiggestUbuntuNoobie Dec 05 '22 at 11:15
  • @fuz your way can't be compiled: `argument of type "unsigned char*" is incompatible with parameter of type "char *"`. After little change `((void (*)(unsigned char *, unsigned char *))decode5a)(srcbuf, dstbuf)` I got another error: `ServerityCodeDescription Project FileLineSUppression State Error C2440 'type cast': cannot convert from 'unsigned char [3500]' to 'void (_cdecl *)(unsigned char *, unsigned char*)'` – BiggestUbuntuNoobie Dec 05 '22 at 11:20
  • @BiggestUbuntuNoobie Try `((void (*)(unsigned char *, unsigned char *))&decode5a)(srcbuf, dstbuf)` perhaps. – fuz Dec 05 '22 at 11:39
  • @BiggestUbuntuNoobie The assembly code calls the contents of `decode5a` as a function, passing `srcbuf` and `dstbuf` as arguments. You can do the same thing in C++. Due to your tags I was thinking you were programming in C, but it seems like you lied about that when you added random tags to your question. – fuz Dec 05 '22 at 11:41
  • @fuz I added C to tags because I know it can be compile with gcc or g++ – BiggestUbuntuNoobie Dec 05 '22 at 11:44
  • @fuz anyway big thanks bro - this void function compiled. Thanks for explaining what that code actually does. It is really helpful! – BiggestUbuntuNoobie Dec 05 '22 at 11:51
  • The level of `asm` support in C and C++ is the same for all practical purposes. – n. m. could be an AI Dec 05 '22 at 11:52
  • but it seems syntax is a little different, isn't? – BiggestUbuntuNoobie Dec 05 '22 at 11:54
  • @BiggestUbuntuNoobie The difference was a type checking issue; C compilers don't care about `unsigned char *` vs. `char *`. Don't add extra language tags because the code could be interpreted as being of that language. Only tag the language you are actually programming in! Otherwise you'll often get useless answers and waste a bunch of time. – fuz Dec 05 '22 at 12:08
  • 1
    The syntax is implementation dependent. – n. m. could be an AI Dec 05 '22 at 12:29

1 Answers1

-2

Here's how you would write that in gcc extended inline assembly, but this still may not work depending on what the function does. In particular, any registers modified by the function have to be listed in the clobbers.

__asm__(
     "push %1\n"
     "push %2\n"
     "call *%0\n"
     "add $8, %%esp \n"
     : : "r"(decode5a), "r"(srcbuf), "r"(dstbuf)
     : "eax", "memory");
fuz
  • 88,405
  • 25
  • 200
  • 352
prl
  • 11,716
  • 2
  • 13
  • 31
  • 2
    Not correct: the function you call may clobber registers which this does not account for. – fuz Dec 05 '22 at 10:54
  • The "memory" clobber is overkill, but an explanation of how to do it properly would be a lot longer and there's already an answer on it somewhere on stackoverflow. – prl Dec 05 '22 at 10:54
  • 2
    It's not overkill. The function may access arbitrary memory. Also note that memory clobbers do not account for clobbered registers. – fuz Dec 05 '22 at 10:55
  • @fuz, yep, I was going to write some assumptions/constraints about the function. – prl Dec 05 '22 at 10:57
  • It is not working. I got this error: `too many memory references for add`. I am trying to compile my file with this command: `gcc -o TestApp.o TestApp.cpp`. Processor is ryzen, 64bit. – BiggestUbuntuNoobie Dec 05 '22 at 11:00
  • 1
    @BiggestUbuntuNoobie This code is for 32 bit, not 64 bit. I've edited the answer to fix this single aspect. The rest is still wrong. – fuz Dec 05 '22 at 11:40
  • 1
    @fuz is correct; this is totally unsafe unless the callee happens not to clobber any registers other than EAX and EFLAGS. You need to tell it about EDX and ECX as well, and all of XMM0-7, st0-7, and k0-7 if AVX-512 is enabled. See [Calling printf in extended inline ASM](https://stackoverflow.com/q/37502841) . At least there are no 32-bit ABIs with a red-zone that this would step on. – Peter Cordes Dec 05 '22 at 14:31
  • Probably best to use dummy output operands for `"=a"(dummy1), "=c"`(dummy2), "=d"`(dummy3)` (not early clobber) so the compiler can still use those 3 regs for `"r"` constraints on input, especially since you need to force register (or immediate) operands not `"rmi"` because you modify ESP before reading all the operands. – Peter Cordes Dec 05 '22 at 14:31
  • @PeterCordes could you give some example how to append it to above code? – BiggestUbuntuNoobie Dec 06 '22 at 09:59