GCC Inline Assembly 'Nd' constraint - gcc

I'm developing a small toy kernel in C. I'm at the point where I need to get user input from the keyboard. So far, I have implemented inb using the following code:
static inline uint8_t inb(uint16_t port) {
uint8_t ret;
asm volatile("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
I know that the "=a" constraint means that al/ax/eax will be copied to ret as output, but I'm still confused about the "Nd" constraint. Can anyone provide some insight on why this constraint is necessary? Or why I can't just use a general purpose register constraint like "r" or "b"? Any help would be appreciated.

The in instruction (returning a byte) can either take an immediate 8 bit value as a port number, or a port specified in the dx register. More on the in instruction can be found in the instruction reference (Intel syntax) . The machine constraints being used can be found in the GCC docs . If you scroll down to x86 family you'll see:
d
The d register
N
Unsigned 8-bit integer constant (for in and out instructions).

Related

How do you explain gcc's inline assembly constraints for the IN, OUT instructions of i386?

As far as I can tell, the constraints used in gcc inline assembly tell gcc where input and output variables must go (or must be) in order to generate valid assembly. As the Fine Manual says, "constraints on the placement of the operand".
Here's a specific, working example from a tutorial.
static inline uint8_t inb(uint16_t port)
{
uint8_t ret;
asm volatile ( "inb %1, %0"
: "=a"(ret)
: "Nd"(port) );
return ret;
}
inb is AT&T syntax-speak for the i386 IN instruction that receives one byte from an I/O port.
Here are the specs for this instruction, taken from the i386 manual. Note that port numbers go from 0x0000 to 0xFFFF.
IN AL,imm8 // Input byte from immediate port into AL
IN AX,imm8 // Input word from immediate port into AX
IN EAX,imm8 // Input dword from immediate port into EAX
IN AL,DX // Input byte from port DX into AL
IN AX,DX // Input word from port DX into AX
IN EAX,DX // Input dword from port DX into EAX
Given a statement like uint8_t x = inb(0x80); the assembly output is, correctly, inb $0x80,%al. It used the IN AL,imm8 form of the instruction.
Now, let's say I just care about the IN AL,imm8 form, receiving a uint8_t from a port between 0x00 and 0xFF inclusive. The only difference between this and the working example is that port is now a uint8_t template parameter (to make it effectively a constant) and the constraint is now "N".
template<uint8_t port>
static inline uint8_t inb()
{
uint8_t ret;
asm volatile ( "inb %1, %0"
: "=a"(ret)
: "N"(port) );
return ret;
}
Fail!
I thought that the "N" constraint would mean, "you must have a constant unsigned 8-bit integer for this instruction", but clearly it does not because it is an "impossible constraint". Isn't the uint8_t template param a constant unsigned 8-bit integer?
If I replace "N" with "Nd", I get a different error:
./test.h: Assembler messages:
./test.h:23: Error: operand type mismatch for `in'
In this case, the assembler output is inb %dl, %al which obviously is not valid.
Why would this only work with "Nd" and uint16_t and not "N" and uint8_t?
EDIT:
Here's a stripped-down version I tried on godbolt.org:
#include <cstdint>
template<uint8_t N>
class Port {
public:
uint8_t in() const {
uint8_t data;
asm volatile("inb %[port], %%al"
:
: [port] "N" (N)
: // clobbers
);
return data;
}
};
void func() {
Port<0x7F>().in();
}
Interestingly, this works fine, except if you change N to anything between 0x80 and 0xFF. On clang this generates a "128 is out of range for constraint N" error. This generates a more generic error in gcc.
Based on how constraints are documented your code should work as expected.
This appears to still be a bug more than a year later. It appears the compilers are converting N from an unsigned value to a signed value and attempting to pass that into an inline assembly constraint. That of course fails when the value being passed into the constraint can't be represented as an 8-bit signed value. The input constraint "N" is suppose to allow an unsigned 8-bit value and any value between 0 and 255 (0xff) should be accepted:
N
Unsigned 8-bit integer constant (for in and out instructions).
There is a similar bug report to GCC's bugzilla titled "Constant constraint check sign extends unsigned constant input operands".
In one of the related threads it was suggested you can fix this issue by ANDing (&) 0xff to the constant (ie: N & 0xff). I have also found that static casting N to an unsigned type wider than uint8_t also works:
#include <cstdint>
template<uint8_t N>
class Port {
public:
uint8_t in() const {
uint8_t data;
asm volatile("inb %[port], %0"
: "=a"(data)
: [port] "N" (static_cast<uint16_t>(N))
: // clobbers
);
return data;
}
};
void func() {
Port<0x7f>().in();
Port<0x80>().in();
// Port<0x100>().in(); // Fails as expected since it doesn't fit in a uint8_t
}
To test this you can play with it on godbolt.

How do memory operands work in avr-gcc inline assembly?

I'm trying to write a custom memory-copy function for AVR as inline assembly, because avr-gcc will always use a loop for memcpy and struct assignment, which is inefficient in terms of time. I want to use memory operands to avoid having to add a "memory" clobber. I currently have this:
void copy_2_bytes (char *restrict dst, char *restrict src)
{
struct S {
char x[2];
};
__asm__(
" ld __tmp_reg__,%[src]+\n"
" st %[dst]+,__tmp_reg__\n"
" ld __tmp_reg__,%[src]+\n"
" st %[dst]+,__tmp_reg__\n"
: [dst] "=m" ( *(struct S *)dst )
: [src] "m" ( *(struct S *)src )
);
}
This compiles, but it's incorrect in general because it modifies the pointer register pairs corresponding to the memory operands. It's easy to see that gcc assumes that the registers stay unchanged, for example by adding "*dst = 0;" after the assembly.
On the other hand, the Y and Z registers support the "ldd" and "std" instructions, which also take an immediate offset, so they can be used to access multiple bytes without being modified. But then there doesn't seem to be a way to force gcc to not select the X register, which doesn't support that.
UPDATE
Actually, if gcc determines that the address of the memory operand is constant, it will pass the constant address into the assembly, instead of a register pair. So now, I have absolutely no idea how to deal with this. Are there some magic instructions or assembly macros which can deal with both pointer registers and constant addresses at the same time?

Which inline assembly code is correct for rdtscp?

Disclaimer: Words cannot describe how much I detest AT&T style syntax
I have a problem that I hope is caused by register clobbering. If not, I have a much bigger problem.
The first version I used was
static unsigned long long rdtscp(void)
{
unsigned int hi, lo;
__asm__ __volatile__("rdtscp" : "=a"(lo), "=d"(hi));
return (unsigned long long)lo | ((unsigned long long)hi << 32);
}
I notice there is no 'clobbering' stuff in this version. Whether or not this is a problem I don't know... I suppose it depends if the compiler inlines the function or not. Using this version causes me problems that aren't always reproducible.
The next version I found is
static unsigned long long rdtscp(void)
{
unsigned long long tsc;
__asm__ __volatile__(
"rdtscp;"
"shl $32, %%rdx;"
"or %%rdx, %%rax"
: "=a"(tsc)
:
: "%rcx", "%rdx");
return tsc;
}
This is reassuringly unreadable and official looking, but like I said my issue isn't always reproducible so I'm merely trying to rule out one possible cause of my problem.
The reason I believe the first version is a problem is that it is overwriting a register that previously held a function parameter.
What's correct... version 1, or version 2, or both?
Here's C++ code that will return the TSC and store the auxiliary 32-bits into the reference parameter
static inline uint64_t rdtscp( uint32_t & aux )
{
uint64_t rax,rdx;
asm volatile ( "rdtscp\n" : "=a" (rax), "=d" (rdx), "=c" (aux) : : );
return (rdx << 32) + rax;
}
It is better to do the shift and add to merge both 32-bit halves in C++ statement rather than inline, this allows the compiler to schedule those instructions as it sees fit.
According to this, this operation clobbers EDX and ECX. You need to mark those registers as clobbered which is what the second one does. BTW, is this the link where you got the above code or did you find it elsewhere? It also shows a few other variaitions for timings as well which is pretty neat.

Loading SSE registers

I'm working on homework project for OS development class. One task is to save context of SSE registers upon interrupt. Now, saving and restoring context is easy (fxsave/fxsave). But I have problem with testing. I want to put same sample date into one of registers, but all I get is error interrupt 6. Here is code:
// load some SSE registers
struct Vec4 {
int x, y, z, w;
} vec = { 0, 1, 2, 3 };
asm volatile ( "movl %0, %%eax"
: /* no output */
: "r"( &vec )
:
);
asm volatile ( "movups (%eax), %xmm0" );
I searched on internet for solution. All I got is that it might something to do with effective address space. But I don't know what it is.
You need to use a memory operand as a constraint in the inline assembly. This is much better than generating the address by yourself (as you tried with the & operator) and loading in in a register, because the latter will not work if the address is rip relative or relocatable.
asm volatile ( "movups %0, %%xmm0"
: /* no output */
: "m"( vec )
:
);
And you need to use two "%%" before register names.
Read more about gcc's constraints here: http://gcc.gnu.org/onlinedocs/gcc/Simple-Constraints.html#Simple-Constraints . The title is somewhat misleading, as this concept is far from simple :-)
I found out what is problem. Execution of SSE instructions must be enabled by setting some flags in CR0 and CR4 registers. More info here: http://wiki.osdev.org/SSE
You're making this way harder than it needs to be - just use the intrinsics in the *mmintrin.h headers, e.g.
#include <emmintrin.h>
__m128i vec = _mm_set_epi32(3, 2, 1, 0);
If you need to put this in a specific XMM register then use the above example as a starting point, then generate asm, e.g. using gcc -S and use the generated asm as a template for your own code.

Any constraints to refer to the high half of a register in gcc inline assembly?

In my C code there are some inlined assembly calling PCI BIOS service. Now the problem is that one of the results is returned in the %ah register, but I can't find a constrant to refer to that register.
What I want is to write like following:
asm("lcall *%[call_addr]" : "something here"(status) :);
and the variable status contains the value of %ah register.
If I use "=a"(status) and add a mov %%ah, %%al instruction it will work. But it seems ugly.
Any suggestions?
I don't think there is a way to specify %ah in a constraint - the GCC x86 backend knows that sub-registers contain particular parts of values, but doesn't really treat them as independent entities.
Your approach will work; another option is to shift status down outside the inline assembler. e.g. this:
unsigned int foo(void)
{
unsigned int status;
asm("movb $0x12, %%ah; movb $0x34, %%al" : "=a"(status) : );
return (status >> 8) & 0xff;
}
...implements the (status >> 8) & 0xff as a single movzbl %ah, %eax instruction.
A third option is to use a small structure:
unsigned int bar(void)
{
struct { uint8_t al; uint8_t ah; } status;
asm("movb $0x12, %%ah; movb $0x34, %%al" : "=a"(status) : );
return status.ah;
}
I'm not sure whether this is nicer or not - it seems a little more self-documenting, but the use of a small structure with a register constraint looks less obviously correct. However, it generates the same code as foo() above.
(Disclaimer: code generation tested with gcc 4.3.2 only; results may well differ on other versions.)

Resources