Switching between Intel and ATT mode in GCC - c

So I have this inline assembly code along with my C code, and I want to use intel syntax for this particular call to asm(), however I need to switch back to ATT syntax or else it will give a long list of errors.
asm(".intel_syntax prefix");
asm volatile (
"add %0, $1 \n\t"
: "=r" (dst)
: "r" (src));
asm(".att_syntax prefix");
Now it gives the following error
/tmp/ccDNa2Wk.s: Assembler messages:
/tmp/ccDNa2Wk.s:180: Error: no such instruction: `movl -16(%ebp),%eax'
/tmp/ccDNa2Wk.s:187: Error: no such instruction: `movl %eax,-12(%ebp)'
I dont understand how to fix the error, i have no call to movl in any part of my code.

Since you haven't yet accepted an answer (<hint><hint>), let me add a third thought:
1) Instead of having 3 asm statements, do it in 1:
asm(".intel_syntax prefix\n\t"
"add %0, 1 \n\t"
".att_syntax prefix"
: "=r" (dst)
: "r" (src));
2) Change your compile options to include -masm=intel and omit the 2 syntax statements.
3) It is possible to support both intel and att at the same time. This way your code works whatever value is passed for -masm:
asm("{addl $1, %0 | add %0, 1}"
: "=r" (dst)
: "r" (src));
I should also mention that your asm may not work as expected. Since you are updating the contents of dst (instead of overwriting it), you probably want to use "+r" instead of "=r". And you do realize that this code doesn't actually use src, right?
Oh, and your original asm is NOT intel format (the $1 is the give-away).

I would try to do the following tests:
In some C code not containing inline assembler insert the line
asm(".att_syntax prefix");
in multiple different locations. Then compile the C code to object files and disassemble these object files (compiling to assembler won't work for this test).
Then compare the disassembly of the original code with the disassembly of the code containing the ".att_syntax" lines.
If the line ".att_syntax prefix" indeed is the correct line for switching back to AT&T mode the disassemblies must be equal AND compiling must work without any errors.
In the next step take your code and compile to assembler instead of object code ("-S" option of GCC). Then you can look at the assembler code.
My idea is the following one:
If you use data exchange in inline assembler ("=r" and "r" for example) GCC needs to insert code that is doing the data exchange:
asm(".intel_syntax prefix");
// GCC inserts code moving "src" to "%0" here
asm volatile (
"add %0, $1 \n\t"
: "=r" (dst)
: "r" (src));
// GCC inserts code moving "%0" to "dst" here
asm(".att_syntax prefix");
This code inserted by GCC is of course in AT&T syntax.
If you want to use Intel syntax in inline assembly you have to use the ".att_syntax" and ".intel_syntax" instructions in the same inline assembly block, just like this:
// GCC inserts code moving "src" to "%0" here
asm volatile (
".intel_syntax prefix \n\t"
"add %0, $1 \n\t"
".att_syntax prefix \n\t"
: "=r" (dst)
: "r" (src));
// GCC inserts code moving "%0" to "dst" here

Related

Return values and constraints for asm (assembler code) using gnu Extended Asm

As a (beginners) exercise I want to implement a swap operation in C using GNU asm.
I'm confused about the restraints. My code is:
int c = 1;
int b = 2;
asm ("xchg %2,%3"
: "=r" (c), "=r" (b)
: "<X>" (c), "<Y>" (b)
);
return c+10*b;
Where $<X>$ and $<Y>$ are replaced by ("0", "0"), ("0", "r"), ("r", "r") and ("r", 0").
("0", "0") does not compile. (Why?)
("0", "r") returns 12, the expected result.
("r", "r") and ("r", "0") return 21, as if nothing happened. (Why?)
So what is wrong in those cases? Why does it fail?
You can use : "+r" (c), "+r" (b) to declare read/write operands1 (https://gcc.gnu.org/onlinedocs/gcc/Modifiers.html) In/out instructions go in the first (output) group of constraints.
And of course you should use xchg %0, %1 to make sure the asm template only references operands you actually declared.
asm ("xchg %0,%1"
: "+r" (c), "+r" (b)
);
Footnote 1: Fun fact: GCC internally implements read/write operand by inventing matching input constraints for these output. So if you didn't fix the %2,%3 in the template, it would still compile. But you wouldn't have any guarantee of which order GCC chose to do the matching constraints in.
To find out what happened with your wrong constraints, make your asm template print the unused operand names as an asm comment, e.g. xchg %2,%3 # inputs= %0,%1 so you can look at the compiler's asm output (gcc -S or on https://godbolt.org), and see which registers it picked. If it picked opposite constraints you'd see no swap.
Or with "r" if it picked 2 registers that are different from the output operands then you're stepping on the compilers toes by modifying registers it expected to remain unchanged (because you told it those were inputs, and could be in separate registers from the outputs.) So no, "r" can't be safe.
If you did want to use matching constraints manually, you'd of course use "0"(c), "1"(b) to force it to pick the same register for c as an input that it picked for c as the output #0, and same for b as input as output #1.
Of course there's no need for a runtime instruction at all to just tell the compiler that C variables have each other's values.
asm ("nop # c input in %2, output in %0. b input in %3, output in %1"
: "=r" (c), "=r" (b)
: "1"(c), "0" (b) // opposite matching constraints
);
Even the nop is unnecessary, but https://godbolt.org/ by default filters comments so it's convenient to put a comment on a NOP.

Gnu as suffix or opperand error

I am getting a suffix or operand error when I compile an old source code. It is generated from an inline assemble code.
ltr (unsigned val)
asm
("ltr %%eax /n/t"
:
: "a" (val)
);
I have read a lot of web pages/forums to find the syntax error but everything tell me the code is correct.
I am using gcc 4.4.1 on Mandriva 10 operating system
Use backslash to end the line.
Secondly it requires 16-bit argument, i.e:
("ltr %%ax \n\t"
Or from memory:
("ltr (%%eax) \n\t"

Inline ASM in C, compiled with MinGW/GCC using "-masm=intel": "undefined reference"

I've been looking around a lot for examples of using inline ASM and I've seen seen a few different approaches.
I've gone with the -masm=intel option when compiling. As I understand it, when using this option you can just write the inline ASM as you would with intel syntax.
I have also seen approaches where people use ".intel_syntax"
When I compile I get the following message.
i586-mingw32msvc-gcc -masm=intel -o KDOS.exe KDOS.c
/tmp/ccVIXhRF.o:KDOS.c:(.text+0x5f): undefined reference to `address'
/tmp/ccVIXhRF.o:KDOS.c:(.text+0x6a): undefined reference to `ipAddr'
/tmp/ccVIXhRF.o:KDOS.c:(.text+0x79): undefined reference to `csAddr'
/tmp/ccVIXhRF.o:KDOS.c:(.text+0x11d): undefined reference to `address'
collect2: ld returned 1 exit status
I've looked around for a solution but I can't seem to find one. I've seen threads saying you can't pass C variables into inline ASM, but I've also seen some stuff saying there are workarounds. They didn't quite apply to what I was doing though so I wasn't really sure what to make of them. Sorry if it is an obvious answer but this is my first time using inline ASM much less fooling around with converting the syntax.
Here is my code. I am working through a book and this is some sample code within it. It was not compiled with gcc in the book so this is why I need to convert to intel syntax, because I need it to run on windows obviously. This is my modified version of the code:
// KDOS.c
// Chapter 2
#include<stdio.h>
#define WORD unsigned short
#define IDT_001_ADDR 0 //start address of first IVT vector
#define IDT_255_ADDR 1020 //start address of last IVT vector
#define IDT_VECTOR_SZ 4 //size of each IVT Vector (in bytes)
#define BP __asm{ int 0x3 } //break point
void main()
{
WORD csAddr; //Code segment of given interrupt
WORD ipAddr; //Starting IP for given interrupt
short address; //address in memory (0-1020)
WORD vector; //IVT entry ID (i.e., 0..255)
char dummy; //strictly to help pause program execution
vector = 0x0;
printf("\n---Dumping IVT from bottom up---\n");
printf("Vector\tAddress\t\n");
for
(
address=IDT_001_ADDR;
address<=IDT_255_ADDR;
address=address+IDT_VECTOR_SZ,vector++
)
{
printf("%03d\t%08p\t",vector,address);
//IVT starts at bottom of memory, so CS is alway 0x0
__asm__
(
".intel_syntax;"
"PUSH ES;"
"MOV AX, 0;"
"MOV ES,AX;"
"MOV BX,address;"
"MOV AX,ES:[BX];"
"MOV ipAddr,AX;"
"INC BX;"
"INC BX;"
"MOV AX,ES:[BX];"
"MOV csAddr,AX;"
"POP ES;"
);
printf("[CS:IP]=[%04X,%04X]\n",csAddr,ipAddr);
}
printf("press [ENTER] key to continue:");
scanf("%c",&dummy);
printf("\n---Overwrite IVT from top down---\n");
/*
Program will die somwhere around 0x4*
Note: can get same results via DOS debug.exe -e command
*/
for
(
address=IDT_255_ADDR;
address>=IDT_001_ADDR;
address=address-IDT_VECTOR_SZ,vector--
)
{
printf("Nulling %03d\t%08p\n",vector,address);
__asm__
(
".intel_syntax;"
"PUSH ES;"
"MOV AX,0;"
"MOV ES,AX;"
"MOV BX,address;"
"MOV ES:[BX],AX;"
"INC BX;"
"INC BX;"
"MOV ES:[BX],AX;"
"POP ES;"
);
}
return;
}/*end main()------------------------------------------------------------*/
Any help would be greatly appreciated. Once again my apologies if it is something obvious.
Actually you can pass C arguments to inline asm. But You have to define it after the asm code part.
In Your case something like this could work (You should add -masm=intel to the gcc's command line):
asm(
".intel_syntax noprefix;\n\t"
...
"MOV BX,%[address];\n\t"
...
".intel_syntax prefix;\n\t"
:: [address] "m" address, ...
: "AX", "BX", /* all changed registers to inform compiler to save them if needed */
);
See examples in a similar question.

what is wrong with following inline assembly code?

What is wrong with the following code?
__asm__("mov %0, %%eax" : :"a" (ptr));
__asm__(".intel_syntax noprefix");//switch to intel syntax.
asm("lidt [eax]");
I get error in compilation like this:
/tmp/cciOoSro.s: Assembler messages:
/tmp/cciOoSro.s:1737: Error: no such instruction: popl %ebp
This is to load interrupt descriptor table IDT for my Os. But seems something wrong. I am not used to at&t syntax. I am used to intel syntax.
the function is to load the pointer of my idt to the processor using lidt.
void setup_idt(uint32 ptr) //to setup the idt i.e to load the idt's pointer
{
__asm__("mov %0, %%eax" : :"a" (ptr));
__asm__(".intel_syntax noprefix");//switch to intel sytax.
__asm__("lidt [eax]");
}
I think the .intel_syntax noprefix line applied to everything until the end of the source. So it tried to interpreted gcc's assembly code as Intel code.
You should:
1. Merge all assembly line into one __asm__ statement (__asm__("line one\n" "line two\n").
2. The last line should do .att_syntax prefix, to return to AT&T syntax.
Or just use AT&T syntax. It isn't so hard.

Replacing inline assembly code

I have to write inline assembly code that executes a custom instruction that I integrated into my hardware.
Depending on what hardware is to find on the actual chip, the instruction behaves differently. My assembly looks as follows:
asm volatile (
" instr_generic %1, %2, %0 \n\t"
: "=r" (c)
: "r" (a), "r" (b)
: "%g0"
);
This instr_generic could now execute either an addition or subtraction for example, depending on what is on the hardware.
Now, instead of instr_generic I wanna write cust_add or cust_sub and this should then be replaced with instr_generic. In other words, it should look like this here
#define cust_add instr_generic
...
asm volatile (
" cust_add %1, %2, %0 \n\t"
: "=r" (c)
: "r" (a), "r" (b)
: "%g0"
);
But I guess I can't use the pre-processor in this context to replace inline assemly is that right? Is there another way to do that easily?
...
#define cust(arg) \
asm volatile (
" " #arg " %1, %2, %0 \n\t" \
: "=r" (c) \
: "r" (a), "r" (b) \
: "%g0" \
)
...
cust(cust_add);
I would either do an if-then-else with the different solutions based on runtime detection of the processor, or to squeeze a little speed, use a function pointer to functions containing the different solution, if detected a then funptr = a_solution, else if detected b then funptr = b_solution, etc. Do that one time then use funptr for the duration of the program.
As already mentioned the custom instruction needs to be compiled at compile time not runtime. if you want to change the instruction runtime that is a third option to do self-modifying code to insert the proper instruction at runtime.
Can't you just use string concatenation? Or is there some reason you can't do it that way?
#define cust_add "instr_generic"
...
asm volatile (
cust_add " %1, %2, %0 \n\t"
: "=r" (c)
: "r" (a), "r" (b)
: "%g0"
);

Resources