annoyingnoob
annoyingnoob

Reputation: 63

Reading variable with inline assembly

I'm wondering, is there a limitation on reading input variables based on the actual instruction?

I'm trying to read an input variable in inline assembly for a .rept directive to repeat an instruction x number of times.

However, the assembler complains with: Error: negative count for REPT - ignored

Here's my approach:

const int x = 42;
__asm__ volatile (".rept %[in]" :: [in] "m" (x));
__asm__ volatile (".endr");

Trying to load the variable value into a register works just as expected:

int function(void) {
    const int x = 42;
    __asm__ volatile ("mov %[in], %%eax" :: [in] "m" (x));
    __asm__ volatile ("ret");
}

returns 42, disassembly looks as expected.

I tried writing this in assembly to see if a constant can be used with .rept directive and it does so indeed

global _start

section .data
    nvalue  equ     39

section .text

_start:
    push    rbp
    mov     rbp,    rsp

    %rep nvalue
        nop
    %endrep

    mov     rax,    60
    mov     rdi,    nvalue
    syscall

Disassembly looks as expected:

Disassembly of section .text:

0000000000401000 <_start>:
  401000:       55                      push   rbp
  401001:       48 89 e5                mov    rbp,rsp
  401004:       90                      nop
  ...
  40102d:       90                      nop
  40102e:       b8 3c 00 00 00          mov    eax,0x3c
  401033:       bf 2a 00 00 00          mov    edi,0x2a
  401038:       0f 05                   syscall

Am I confusing .rept with %rep and do they not represent identical operation?

Any help will be greatly appreciated.

Upvotes: 1

Views: 1229

Answers (1)

Nate Eldredge
Nate Eldredge

Reputation: 58052

As mentioned in comments, an i operand will normally be inserted with a leading $ sign, which is correct as an immediate operand in AT&T syntax but not good for an assembler directive like .rept. You can suppress this with the c modifier, see Section 6.47.2.8 of the GCC manual:

void many_nops(void) {
    const int num = 42;
    asm(".rept %c0 ; nop ; .endr" : : "i" (num));
}

This will inline 42 nop instructions. Of course this will only work if num can be folded as a compile-time constant; in particular you must compile with optimization for it to work.

Try on godbolt

You could also use Intel asm syntax with -masm=intel, in which constants don't get a leading $ in the first place.

Note that there are a number of other problems with your inline asm (you can't ret from inline asm, shouldn't split code between multiple asm statements, etc.) so you might want to start by reading some of the FAQs at https://stackoverflow.com/tags/inline-assembly/info.

The issue with .rept versus %rep: the first is the correct syntax for the GNU assembler gas which is normally used for assembling GCC output, and the second is for the nasm assembler.

Upvotes: 4

Related Questions