0

What would be the simplest way to directly run an assembly instruction from within a C program? For example, I stubbed out an example to do the following:

#include <stdio.h>

int plus_one_times_two(int x)
{
    // plus one -- in asm
    // argument passed in %rdi, so how to do: `inc %rdi` ? from C

    // times two -- in c
    x = x*2;

    return x;
}

int main(void)
{
    int x=5;
    int y=plus_one_times_two(x);
    printf("X: %d | (X+1)*2: %d\n", x, y);
}

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
samuelbrody1249
  • 4,379
  • 1
  • 15
  • 58
  • Why can’t you just do `x++;`? – user3840170 Jan 21 '21 at 20:23
  • @user3840170 it's an exercise to see how to do it. Of course I could do that, and I wouldn't even use a function, and would just inline the arithmetic: `(x*2)+1`. – samuelbrody1249 Jan 21 '21 at 20:26
  • Why do you want to code in assembly? There are few reasons to *code* in assembly. You may want to *read* assembly code produced by a compiler! Most laptops or desktops are x86-64 (the 32 bits variant x86 is rare in 2021), and most tablets have ARM processors. – Basile Starynkevitch Jan 21 '21 at 20:43

1 Answers1

-3

Use asm() for inline assembly:

asm("inc %rdi");

See this guide for more info.

EDIT: As has been pointed out in the comments, this is not something you should ever do. You shouldn't be using inline assembly in C code unless there's some specific thing you're trying to do that you can't do in plain C, and this is not one of those things.

johnmastroberti
  • 847
  • 2
  • 12
  • thanks, and if I wanted to write that back to `x` how would I do that inline? – samuelbrody1249 Jan 21 '21 at 20:20
  • The `inc` instruction increments the contents of the `%rdi` register and _and_ stores it back into the `%rdi` register. This is how most assembly instructions work; the result is stored back into one of the arguments to the instruction. The value is not returned from the `asm()` "function call". – johnmastroberti Jan 21 '21 at 20:24
  • Right, I mean how to write the value in `%rdi` (after it's incremented) back into the `x` variable from above. – samuelbrody1249 Jan 21 '21 at 20:27
  • 1
    @samuelbrody1249: This is completely unsafe and broken. This increments the *register*, but it doesn't tell the C compiler that you want this to happen while the C variable is in RDI, or that it modifies a register. See https://stackoverflow.com/tags/inline-assembly/info for links to guides. GNU C Basic asm statements like this can't safely be used to modify C variables, or really for anything except the body of an `__attribute__((naked))` function. See also https://gcc.gnu.org/wiki/ConvertBasicAsmToExtended. You need GNU C Extended asm, like the guide linked in the answer explains! – Peter Cordes Jan 21 '21 at 20:30
  • 1
    @john re: your edit: There are safe ways to modify C variables, e.g. `asm("inc %0" : "+r"(var));`. It's true that there's no need to use inline asm (https://gcc.gnu.org/wiki/DontUseInlineAsm) for this, but that wasn't my point. More importantly that this is not a safe example. There are safe ways to do this, but this isn't one of them. – Peter Cordes Jan 21 '21 at 20:38
  • 1
    However, if you're trying to learn asm, it's generally better to write whole functions in asm. Once you understand that, and calling conventions with clobbered vs. preserved registers, that's a good basis for understanding how to describe your code to the compiler with GNU C Extended asm constraints, if you really want to learn inline asm for some reason. – Peter Cordes Jan 21 '21 at 20:41
  • @PeterCordes thanks, I got it to work with: `asm("inc %0;"` `"add %0, %0;"` `:"=r"(x)` `:"r" (x)` `);`. What does the `"+r"` mean? I've been having some tough time finding information on how the input/output formats work (even that GNU page only shows `=r`. – samuelbrody1249 Jan 21 '21 at 20:47
  • 1
    @samuelbrody1249: You're assuming the compiler will pick the same register for the `"r"` input (%1) as the `"=r"` output (%0). That's not guaranteed, so your code will break easily. Read the GCC manual, https://gcc.gnu.org/onlinedocs/gcc/Modifiers.html. Or read the various linked duplicate answers of this SO question. – Peter Cordes Jan 21 '21 at 20:51
  • 1
    @samuelbrody1249: Actually none of the linked duplicates used `+r`, they mostly used stupid `mov` instructions. See [How does "+&r" differ from "+r"?](https://stackoverflow.com/q/45895564). IDK if you tried googling for `site:stackoverflow.com inline assembly "+r"` but I did and got several hits besides that one. – Peter Cordes Jan 21 '21 at 20:53
  • @PeterCordes thanks for that. So is `asm("inc %1; add %1, %1;" :"=r"(y) :"r"(x));` better for doing `y=(x+1)*2` ? – samuelbrody1249 Jan 21 '21 at 20:58
  • 1
    @samuelbrody1249: No, of course not. Now you're only referencing the input operand, not the output operand, so it's even more broken (modifying an input) if the compiler doesn't pick the same register for both operands. If you want to let the compiler pick separate operands, use something that can copy-and-operate like `asm("lea 2(%q1, %q1), %0" : "=r"(out) : "r"(in))` which should let the compiler do `lea 2(%rdi,%rdi), %eax`. (Note the q modifier on %1 in the template: an address-size prefix would be wasted here to actually encode %edi in the addressing mode). https://godbolt.org/z/Kr6z9K – Peter Cordes Jan 21 '21 at 21:24