Thread: [Inline Assembly] What am I doing wrong in this function?

  1. #1
    Registered User
    Join Date
    Oct 2021
    Posts
    129

    [Inline Assembly] What am I doing wrong in this function?

    I'm trying to learn assembly and I'm trying to covert a function using inline assembly. The function I want to convert is the following:

    Code:
    void no_asm_ver() {
      int first_number = 0, second_number = 1, third_number, i;
    
      for(i = 2; i < 20; ++i) {
        third_number = first_number + second_number;
        printf("%d ", third_number);
        first_number = second_number;
        second_number = third_number;
      } fflush(stdout); write(1, "\n", 1);
    }
    So I want to convert this to assembly (except for the loop and the last line where it flushes "stdout" and prints a newline). I tried to do the following:

    Code:
    void asm_ver() {
      const void* prompt = "%d ";
      asm (
        "mov $0, %r15;" // frist_number
        "mov $1, %r14;" // second_number
        // "mov $0, %r13;" // third_number
      );
    
      int i;
    
      for(i = 2; i < 20; ++i) {
        asm volatile (
          // third_number = first_number + second_number
          "mov %r15, %r13;"
          "add %r14, %r13;"
    
          // printf("%d", third_number);
          "mov %r13, %rsi;"
          "call printf;"
    
          // first_number = second_number
          "mov %r14, %r15;"
    
          // second_number = third_number
          "mov %r13, %r14;"
    
          :: "D" (prompt)
        );
      } fflush(stdout); write(1, "\n", 1);
    }
    I've used "r13-r15" for the variables. For "printf", I've seen a post (link in the bottom of this post) about the calling convention for functions so I'm trying to pass the first parameter (prompt) in the "rdi" register and the second parameter (third_num) in the "rsi" register and then call "printf". If I remove the last line from the "asm" statement (:: "D" (prompt)) then it will work. But now, I'm getting the following error message in GCC:

    Code:
    test.c: In function ‘asm_ver’:
    test.c:67:5: error: invalid 'asm': operand number out of range
       67 |     asm volatile (
          |     ^~~
    test.c:67:5: error: invalid 'asm': operand number out of range
    test.c:67:5: error: invalid 'asm': operand number out of range
    test.c:67:5: error: invalid 'asm': operand number out of range
    test.c:67:5: error: invalid 'asm': operand number out of range
    test.c:67:5: error: invalid 'asm': operand number missing after %-letter
    test.c:67:5: error: invalid 'asm': operand number out of range
    test.c:67:5: error: invalid 'asm': operand number out of range
    test.c:67:5: error: invalid 'asm': operand number out of range
    test.c:67:5: error: invalid 'asm': operand number out of range

    In TCC, the message is the following:

    Code:
    test.c:83: error: invalid operand reference after %
    So none of them are very informative about what I'm doing wrong. Any ideas? Is there a chane that it doesn't like that I'm using the "r" registers...

    Link for the post talking about the calling conversion: X86-64 assembly from scratch - Conrad Kleinespel

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,426
    Extended Asm (Using the GNU Compiler Collection (GCC))
    This suggests you need to add some \n\t to get proper lines and indentation.

    Otherwise the assembler just sees one long line and barfs on it.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Oct 2021
    Posts
    129
    Quote Originally Posted by Salem View Post
    Extended Asm (Using the GNU Compiler Collection (GCC))
    This suggests you need to add some \n\t to get proper lines and indentation.

    Otherwise the assembler just sees one long line and barfs on it.
    I added them but this doesn't seem to fix anything. I also don't understand why seeing it as a long line will not work as there are semicolons to indicate the end of an instruction.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,426
    Maybe your x86 doesn't have registers called r13, r14, r15 etc.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Dec 2017
    Posts
    1,466
    Does this work:
    Code:
    #include <stdio.h>
     
    int main()
    {
        int src = 1, dst;
     
        __asm__(
            "mov %1, %0\n\t"  // dst = src
            "add $1, %0"      // ++dst
            : "=r" (dst)
            : "r" (src));
     
        printf("%d\n", dst);
        return 0;
    }
    The whole problem with the world is that fools and fanatics are always so certain of themselves, but wiser people so full of doubts. - Bertrand Russell

  6. #6
    Registered User
    Join Date
    Oct 2021
    Posts
    129
    Quote Originally Posted by Salem View Post
    Maybe your x86 doesn't have registers called r13, r14, r15 etc.
    My whaaaaaat????? My CPU is Ryzen 5 2400G

    Also, I know that I was the one that originally thought that but tbh, it doesn't make sense as it works without the last line of the asm statement so I don't think that this is the problem...

  7. #7
    Registered User
    Join Date
    Oct 2021
    Posts
    129
    Quote Originally Posted by john.c View Post
    Does this work:
    Code:
    #include <stdio.h>
     
    int main()
    {
        int src = 1, dst;
     
        __asm__(
            "mov %1, %0\n\t"  // dst = src
            "add $1, %0"      // ++dst
            : "=r" (dst)
            : "r" (src));
     
        printf("%d\n", dst);
        return 0;
    }
    Thanks you, this works but not for my example. "r" let's the compiler choose a register and I want to use specif ones in this case. I mean, this would probably be OK to make my code but It will be a good practice to find and fix my code so I can properly learn. In any case, thank you!

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,426
    This seemed to work, doubling up the %
    But only in the 2nd example.
    Code:
    void asm_ver() {
      const void* prompt = "%d ";
      asm (
        "mov $0, %r15\n\t" 
        "mov $1, %r14\n\t"
      );
     
      int i;
     
      for(i = 2; i < 20; ++i) {
        asm volatile (
          "mov %%r15, %%r13\n\t"
          "add %%r14, %%r13\n\t"
     
          "mov %%r13, %%rsi\n\t"
          "call printf\n\t"
     
          "mov %%r14, %%r15\n\t"
     
          "mov %%r13, %%r14\n\t"
     
          :: "D" (prompt)
        );
      }
    }
    
    $ gcc -c -S foo.c
    $ cat foo.s
    << snipped >>
    #APP
    # 3 "foo.c" 1
    	mov $0, %r15
    	mov $1, %r14
    	
    # 0 "" 2
    #NO_APP
    
    #APP
    # 11 "foo.c" 1
    	mov %r15, %r13
    	add %r14, %r13
    	mov %r13, %rsi
    	call printf
    	mov %r14, %r15
    	mov %r13, %r14
    	
    # 0 "" 2
    #NO_APP
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  9. #9
    Registered User
    Join Date
    Oct 2021
    Posts
    129
    Quote Originally Posted by Salem View Post
    This seemed to work, doubling up the %
    But only in the 2nd example.
    Code:
    void asm_ver() {
      const void* prompt = "%d ";
      asm (
        "mov $0, %r15\n\t" 
        "mov $1, %r14\n\t"
      );
     
      int i;
     
      for(i = 2; i < 20; ++i) {
        asm volatile (
          "mov %%r15, %%r13\n\t"
          "add %%r14, %%r13\n\t"
     
          "mov %%r13, %%rsi\n\t"
          "call printf\n\t"
     
          "mov %%r14, %%r15\n\t"
     
          "mov %%r13, %%r14\n\t"
     
          :: "D" (prompt)
        );
      }
    }
    
    $ gcc -c -S foo.c
    $ cat foo.s
    << snipped >>
    #APP
    # 3 "foo.c" 1
        mov $0, %r15
        mov $1, %r14
        
    # 0 "" 2
    #NO_APP
    
    #APP
    # 11 "foo.c" 1
        mov %r15, %r13
        add %r14, %r13
        mov %r13, %rsi
        call printf
        mov %r14, %r15
        mov %r13, %r14
        
    # 0 "" 2
    #NO_APP
    This.... WORKS! What? Why it works now? The documentation needs to be bigger and include way more examples... Anyway, I plan on making my own compiler and I'm learning how to create ELF files so I should probably not bother with GCC inline assembly at all.

    Once again, thank you for your help!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Inline assembly error
    By TheEngineer in forum C Programming
    Replies: 9
    Last Post: 05-06-2010, 08:52 AM
  2. inline assembly
    By seizmic in forum C++ Programming
    Replies: 8
    Last Post: 09-30-2005, 09:21 AM
  3. Inline assembly
    By ^xor in forum C Programming
    Replies: 13
    Last Post: 07-05-2005, 06:32 AM
  4. inline assembly in dev-cpp
    By variable in forum C Programming
    Replies: 4
    Last Post: 02-16-2005, 10:27 PM
  5. Inline Assembly?
    By AlenM in forum C++ Programming
    Replies: 5
    Last Post: 12-07-2001, 12:08 PM

Tags for this Thread