9

i use vscode with gcc on windows. i know that it is possible to write a c++ function and use asm("code"), however i came accross the following yt video:https://www.youtube.com/watch?v=7Xe9pCrzH98 where the author showcases the following c++ code:

__asm int sum4(int a,int b,int c,int d){
PUSH {r4, lr}
MOV r4, r0
ADD r4, r4, r1
ADD r4, r4, r2
ADD r0, r4, r3
POP {r4, pc}
}

which defines an entire asm function, instead of defining a c++ function with inside it the asm keyword, however i have not been able to replicate this. is it possible and does it even make a difference? i would imagine the compiler might add things for a c++ function

extern "C" int ret100(void);
__asm(
"ret100:\n"
"  mov $100,%rax\n"
"  ret\n"
);

works so i tried various variations of

__asm int ret100(){
"mov $100,%rax\n"
"ret"
}

to no avail

edit: solution: i dont know if it is still possible to define a full asm function, however you can make the function naked, which means it doesnt create a pro and -epilogue, this can be done with __delspec( naked ) and thus the following function:__declspec( naked ) int ret100(void){asm("mov $100, %eax\nret\n");} creates an asm function with only the two asm statements in the body. credit to Jester

naked function wiki:learn.microsoft.com/en-us/cpp/cpp/naked-cpp?

  • 2
    It's possible, but not all that useful in practice. For example `return 100;` can be written just as well in C++. :-) Also, some of the "special instructions" referred to in the video are already available in the [``](https://en.cppreference.com/w/cpp/header/bit) header. – BoP Aug 06 '23 at 19:04
  • 2
    The actual examples shown in that youtube video are *not* useful for performance, only for understanding some basics like linker and symbol stuff. `__bultin_clz` will compile to an ARM `clz` instruction, and libc `strlen` is implemented much more efficiently than `ldrb` one byte at a time (especially on x86 where branching on a SIMD compare result can be done efficiently, vs. some ARM CPUs stalling the pipeline on SIMD -> integer data movement.) – Peter Cordes Aug 06 '23 at 19:24
  • 1
    The example from the YouTube video looks like it is ARM code for use with the armcc compiler. The syntax and features are completely different than for gcc / x86. Always remember that assembly language varies between architectures, and between different assemblers (and compilers, in the case of inline assembly) for the same architecture. If you just do searches for "how to do X in assembly language" you may well find a different architecture/assembler/compiler combination, which will be useless to you. You'd want to add something like "gcc x86-64" to your query. – Nate Eldredge Aug 06 '23 at 19:53

3 Answers3

7

You want a naked function, e.g.:

__attribute__((naked))
int ret100(void)
{
    __asm__(
        "mov $100, %eax\n"
        "ret\n"
    );
}
Jester
  • 56,577
  • 4
  • 81
  • 125
  • 1
    Since it's C++ you could skip `void` – Ted Lyngmo Aug 06 '23 at 18:57
  • Shouldn't you use `__attribute__((naked))` on both the prototype and definition? You also don't *need* a separate prototype, except in other compilation units. – Peter Cordes Aug 06 '23 at 19:11
  • 1
    @PeterCordes gcc says _"attributes are not allowed on a function-definition"_ if they are not separated. – Ted Lyngmo Aug 06 '23 at 19:12
  • 3
    @TedLyngmo: Did you try to put the attribute right before the `{` or something? On definitions, they go before the function name, e.g. https://godbolt.org/z/Y66fzbxjE `__attribute__((naked)) int ret100(void) { ... }`. And yes, it works there. If omitted, G++ would warn about falling off a non-`void` function without a `return`. – Peter Cordes Aug 06 '23 at 19:15
  • @PeterCordes Cool, no I did not try that. Great! – Ted Lyngmo Aug 06 '23 at 19:16
4

A better way to do this would be putting your ASM function in .S file and compile it as such (GCC will pick up this is in assembly when you include it during compilation, ie. g++ main.cpp func.S -o app). Just don't forget to declare your function as extern "C" so that its name doesn't get mangled and it would be picked up by linker correctly.

Example:

main.cpp:

#include <iostream>

extern "C"
{
extern int func();
}

int main()
{
    auto val = func();
    std::cout << val << std::endl;
    return 0;
}

func.S:

.global func

func:
    mov $100, %eax
    ret
PookyFan
  • 785
  • 1
  • 8
  • 23
  • 1
    But the question OP asked was _"is it possible to define a full assembly function in a c++ file"_ and I don't think this answers that question, even if it's probably good advice. – Ted Lyngmo Aug 06 '23 at 19:20
  • 5
    @TedLyngmo perhaps. It's up to OP to decide whether this is useful or not, I just wanted to share a better way of doing things. – PookyFan Aug 06 '23 at 19:22
3

There's no portable way to use inline asm inside C++ source files. Some compilers support it. Some compilers don't support it. The compilers that do support it mostly have different syntax for doing so (and the support may even differ for 32 and 64 bit versions of the compiler - for example).

Once you go with asm you've left portability behind and you are dealing with implementation details of your chosen toolchain/platform, so you'll have to look up for each platform/toolchain how to do it and use the required syntax for each.

Jesper Juhl
  • 30,449
  • 3
  • 47
  • 70