2

How to write multiple assembly statements within asm() without "\t\n" separating each line using GCC?

I've seen some textbooks write multiple assembly statements within asm() as:

asm("
movl $4, %eax
movl $2, %ebx
addl %eax, %ebx
...
");

However, my compiler (GCC) doesn't recognize this syntax. Instead, I must rely on "\t\n" separating each line or using multiple asm():

asm(
"movl $4, %eax\t\n"
"movl $2, %ebx\t\n"
"addl %eax, %ebx\t\n"
...);

or

asm("movl $4, %eax");
asm("movl $2, %ebx");
asm("addl %eax, %ebx");
...

How do I enable the "clean" syntax with no "\t\n" or repeated asm()?

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
Shuzheng
  • 11,288
  • 20
  • 88
  • 186
  • 3
    And what is your problem? The syntax is "clean" with the linebreaks. Not sure why you use the tabs. Inline-assembly should be used sparesly and only for short snippets anyway **if unavoidable**. – too honest for this site Mar 27 '17 at 17:51
  • 6
    I would argue that the correct solution is to *not* use inline assembly to begin with. :) – Some programmer dude Mar 27 '17 at 17:51
  • @Olaf - I don't want to repeatedly write "\n"? – Shuzheng Mar 27 '17 at 17:52
  • 3
    The solution is simple: use a seperate assembly file. – too honest for this site Mar 27 '17 at 17:54
  • Don't write long code inline, thus you won't have to type many `\n` ;) – Jester Mar 27 '17 at 17:54
  • @Olaf - and then link and call the functions defined in this file? – Shuzheng Mar 27 '17 at 17:55
  • I'm not sure whether the inline asm block supports raw string literals, but give it a try. – The Techel Mar 27 '17 at 18:00
  • 1
    Why don't you just write clear, maintainable C++ instead and let the compiler worry about the asm? Unless you are doing something *really* low level or optimizing a *really* critical function (and *really* know what you are doing) the compiler is probably going to write better asm than you anyway. – Jesper Juhl Mar 27 '17 at 18:00
  • 1
    imho it is a bit funny that you want to write assembler and you are worrying about a line break. I would rather worry about everything else in that block ;) – 463035818_is_not_an_ai Mar 27 '17 at 18:02
  • 6
    What sort of advice is 'you should never write assembler'? Jeez, hasn't anyone here ever experimented? – James Mar 27 '17 at 21:42
  • Possible duplicate of [Can I write multiple Assembly instructions on the same line?](https://stackoverflow.com/questions/27685548/can-i-write-multiple-assembly-instructions-on-the-same-line) – phuclv Jul 03 '18 at 02:43

2 Answers2

3

GCC

Your inline assembly is ill advised since you alter registers without informing the compiler. You should use GCC's extended inline assembler with proper input and output constraints. Using inline assembler should be used as a last resort and you should understand exactly what you are doing. GCC's inline assembly is very unforgiving, as code that seems to work may not even be correct.

With that being said ending each string with \n\t makes the generated assembler code look cleaner. You can see this by compiling with the -S parameter to generate the corresponding assembly code. You do have the option of using a ; (semicolon). This will separate each instruction but will output all of the instructions on the same assembler line. And yes this matters: looking at the -S output is a good way to see how the compiler substituted operands into your asm template and put its own code around yours.

Another option is to use C line continuation character \ (backslash). Although the following will generate excessive white space in generate assembly code it will compile and assemble as expected:

int main()
{
    __asm__("movl $4, %eax; \
             movl $2, %ebx; \
             addl %eax, %ebx"
          ::: "eax", "ebx");
}

Although this is a way of doing it, I'm not suggesting that this is good form. I have a preference for the form you use in your second example using \n\t without line continuation characters.


Regarding splitting up multiple instructions into separate ASM statements:

asm("movl $4, %eax");
asm("movl $2, %ebx");     // unsafe, no operands specifying connections
asm("addl %eax, %ebx");

This is problematic. The compiler can reorder these relative to one another since they are basic assembler with no dependencies. It is possible for a compiler to generate this code:

movl $4, %eax
addl %eax, %ebx
movl $2, %ebx

This of course would not generate the result you expect. When you place all the instructions in a single ASM statement they will be generated in the order you specify.


MSVC/C++

32-bit Microsoft C and C++ compilers support an extension to the language that allows you to place multi-line inline assembly between __asm { and }. Using this mechanism you don't place the inline assembly in a C string; don't need to use line continuation; and no need to end a statement with with a ; (semicolon).

An example of this would be:

__asm {
    mov eax, 4
    mov ebx, 2
    add ebx, eax
}
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Michael Petch
  • 46,082
  • 8
  • 107
  • 198
  • 3
    Thank you @Michael - Finally an answer that address my question. – Shuzheng Mar 27 '17 at 20:04
  • Still I find it weird that, e.g. The Shellcoder Hacker's Handbook, use the syntax I mention first. – Shuzheng Mar 27 '17 at 20:11
  • @Shuzheng I only had access to the second edition of the Shellcoders handbook (online) and it is clear they have made some errors in that regard. In the second edition though they get the syntax correct in Chapter 4 page 79 in the example. In that case they use the backslash line continuation character and ended each line with a `;` as I did in my answer, but I'm not personally fond of doing it that way. – Michael Petch Mar 27 '17 at 21:28
  • 1
    using `asm volatile` forces the compiler to generate the code in order – Alexis Jun 14 '20 at 06:43
  • `asm("")` is implicitly `volatile`; reordering isn't the problem (except with buggy compilers; lack of clobber declarations means it can't be safely used inside a non-`naked` function – Peter Cordes Jun 19 '21 at 00:44
0

You can also just do...

int main()
{
    __asm__(
            "movl $4, %eax;"
            "movl $2, %ebx;"
            "addl %eax, %ebx;"
           );
}
n c
  • 45
  • 1
  • 7