Page 1 of 1

Utilizing Inline Assembly parameters

Posted: Thu Jan 14, 2021 2:19 pm
by TheGameMaker90
Hello again all,
My question today is this: If I were to pass a value in inline assembly such as
asm volatile("int $0x0"); How would I pass a parameter to the $0x0 part in inline assembly?

I'm trying to understand it in its entirety so that I can utilize it wherever I see fit. For some reason, even with all my programming experience (10+ years since childhood), I can't process it. Perhaps somebody on these forums could shed some light on it so I understand its use and such. For the record I'm using GCC and in the flags I have -std=gnu99 so I'm using C99, if that helps.

Thanks.

P.S. An example would be greatly parreciated, but please explain it so I can understand rather than just copy/paste without context. Thanks.

Re: Utilizing Inline Assembly parameters

Posted: Thu Jan 14, 2021 2:23 pm
by iansjack

Re: Utilizing Inline Assembly parameters

Posted: Thu Jan 14, 2021 2:28 pm
by TheGameMaker90
iansjack wrote:Have you read the documentation?

https://gcc.gnu.org/onlinedocs/gcc/Usin ... ith-C.html
Was just on that page, problem is, I'm not understanding what I'm reading and I'm strapped for time.
Again I refer to the example, let's put it this way: How would I pass a uint8_t into inline assembly in the form of "$0x0"

void pass_value(uint8_t val)
{
asm volatile ("int %0" : :"a"(val));
}

doesn't seem to work. I just need to know what %0 should be if not that.

Re: Utilizing Inline Assembly parameters

Posted: Thu Jan 14, 2021 2:53 pm
by Octocontrabass
It's not possible. The INT instruction only accepts an immediate operand, which must be a compile-time constant. You can't use a variable there.

Re: Utilizing Inline Assembly parameters

Posted: Thu Jan 14, 2021 4:42 pm
by TheGameMaker90
Octocontrabass wrote:It's not possible. The INT instruction only accepts an immediate operand, which must be a compile-time constant. You can't use a variable there.
Ah, that's what i thought, I couldn't find anything on the subject. Thank you.

Re: Utilizing Inline Assembly parameters

Posted: Fri Jan 15, 2021 6:00 am
by iansjack
Could you amplify a little the way that you want to use the parameter? If it is a true variable then, as said, you can't do it. But if you want to use the parameter in a way that you might use an assembler macro, passing a known constant as the interrupt number, then it can be done. For example, if you want to write something like:

Code: Select all

.macro interrupt number rega
   move \rega, %eax
   int $\number
.endm

...

int x = 2;
interrupt $1, x;
interrupt $2, x;

etc.
then that's no problem.

I can't think why you would want the interrupt number to be a true variable, but perhaps you could explain your requirements.

Re: Utilizing Inline Assembly parameters

Posted: Fri Jan 15, 2021 9:01 am
by TheGameMaker90
iansjack wrote:Could you amplify a little the way that you want to use the parameter? If it is a true variable then, as said, you can't do it. But if you want to use the parameter in a way that you might use an assembler macro, passing a known constant as the interrupt number, then it can be done. For example, if you want to write something like:

Code: Select all

.macro interrupt number rega
   move \rega, %eax
   int $\number
.endm

...

int x = 2;
interrupt $1, x;
interrupt $2, x;

etc.
then that's no problem.

I can't think why you would want the interrupt number to be a true variable, but perhaps you could explain your requirements.
Let's put it this way, rather than overcomplicating it, I just want a faster easier way of doing asm volatile("int $x");
I figured I'd pass a C parameter to the int number so I don't have to write asm volatile every time.

Actually I think you just gave me an idea, I'll check back on the status (if it worked or not).

Edit:
Nope, I tried doing it from one of my asm files and "invalid combination of opcode and operand." It's not super important, just a time saver. And I think Octocontrabass is right. It was worth a shot though.

Re: Utilizing Inline Assembly parameters

Posted: Fri Jan 15, 2021 9:40 am
by iansjack
Why not use a C macro?

Re: Utilizing Inline Assembly parameters

Posted: Fri Jan 15, 2021 11:32 am
by moonchild

Code: Select all

#define intn(n) __asm__ volatile ("int " #n)
(Replace 'int ' with 'int $' if not using -masm=intel.)

Re: Utilizing Inline Assembly parameters

Posted: Sat Jan 16, 2021 1:57 pm
by TheGameMaker90
moonchild wrote:

Code: Select all

#define intn(n) __asm__ volatile ("int " #n)
(Replace 'int ' with 'int $' if not using -masm=intel.)
:shock: You were right! Wow, so can this be used anywhere? (Or almost anywhere)?
And if you would, please explain the "#n" in the expresion. Is that a reference to a memory address? Or just a hex value representing a number? Just for thoroughness and completeness.

Re: Utilizing Inline Assembly parameters

Posted: Sat Jan 16, 2021 2:06 pm
by TheGameMaker90
iansjack wrote:Why not use a C macro?
Because I plan to switch all of my NASM assembly to GAS assembly at some point and it would just be too complicated to convert over. Plus I am looking for a way to do as much as possible in inline assembly (or GAS technically), that would be too much to write in a C file. I appreciate it though and may use your idea for something else at some point.

Re: Utilizing Inline Assembly parameters

Posted: Sat Jan 16, 2021 7:57 pm
by MichaelPetch
If you ever wanted a version where the interrupt number isn't known at compile time you can do something like this (it avoids self modifying code) using a jump table:

Code: Select all

/* We use GNU assembly to create a table of interrupt calls followed by a ret
 * using the .rept directive. 256 entries (0 to 255) are generated.
 * generate_interrupt is a simple function that takes the interrupt number
 * as a parameter, computes the offset in the interrupt table and jumps to it.
 * The specific interrupted needed will be called followed by a RET to return
 * back from the function */

extern void generate_interrupt(unsigned char int_no);
asm (".pushsection .text\n\t"

     /* Generate the table of interrupt calls */
     ".align 4\n"
     "int_jmp_table:\n\t"
     "intno=0\n\t"
     ".rept 256\n\t"
         "\tint $intno\n\t"
         "\tret\n\t"
         "\t.align 4\n\t"
         "\tintno=intno+1\n\t"
     ".endr\n\t"

     /* generate_interrupt function */
     ".global generate_interrupt\n"      /* Give this function global visibility */
     "generate_interrupt:\n\t"
#ifdef __x86_64__
     "movzx %dil, %edi\n\t"              /* Zero extend int_no (in DIL) across RDI */
     "lea int_jmp_table(%rip), %rax\n\t" /* Get base of interrupt jmp table */
     "lea (%rax,%rdi,4), %rax\n\t"       /* Add table base to offset = jmp address */
     "jmp *%rax\n\t"                     /* Do sepcified interrupt */
#else
     "movzxb 4(%esp), %eax\n\t"          /* Get Zero extend int_no (arg1 on stack) */
     "lea int_jmp_table(,%eax,4), %eax\n\t"
                                         /* Compute jump address */
     "jmp *%eax\n\t"                     /* Do specified interrupt */
#endif
     ".popsection");

int main()
{
    generate_interrupt (0);
    generate_interrupt (3);
    generate_interrupt (255);
}
Yes it is ugly ;-). This version doesn't use a function with naked attribute since I wrote this at a time when that attribute wasn't available on the x86 targets. I never used this myself, and was an example of how it could be done. If you compile it to an object file and review the generated code with OBJDUMP the function that is generated may make more sense. `generate_interrupt` in this case can take a variable as a parameter as well and doesn't require a constant value at run time. This kind of thing is uncommon though.

Re: Utilizing Inline Assembly parameters

Posted: Sun Jan 17, 2021 1:09 am
by iansjack
TheGameMaker90 wrote:
iansjack wrote:Why not use a C macro?
Because I plan to switch all of my NASM assembly to GAS assembly at some point and it would just be too complicated to convert over. Plus I am looking for a way to do as much as possible in inline assembly (or GAS technically), that would be too much to write in a C file. I appreciate it though and may use your idea for something else at some point.
But that's exactly where a C macro, such as the example given by moonchild, helps by limiting the change to a single line of code in a header file.