Set register using a variable inline assembly - c

My requirement is to set EDI register using a variable with inline assembly. I wrote the following snippet but it fails to compile.
uint32_t value = 0;
__asm__ __volatile__("mov %1,%%edi \n\t"
: "=D"
: "ir" (value)
:
);
Errors I get are
cyg_functions.cpp(544): error: expected a "("
: "ir" (value)
^
cyg_functions.cpp(544): internal error: null pointer
: "ir" (value)
Edit
I guess I wasn't clear on the problem specification. Let's say my requirement is as follows.
There are two int variables val and result.
I need to
Set the value of variable val to %%edi clobbering whatever in there already
Multiply %%edi value by 2
Set %%edi value back to result variable
How can this be stated with inline assembly? Though this is not exactly my requirement answer to this (specifically the 1st step) would solve my problem. I need the intermediate to be specifically in EDI register.

I have read your comments, and the requirements here still makes no sense to me. However, making sense is not a requirement. Such being the case:
int main(int argc, char *argv[])
{
int res;
int value = argc;
asm ("shl $1, %[res]" /* Take the value in res (aka EDI) and shift
it left by 1. */
: [res] "=D" (res) /* On exit from the asm, the register EDI
will contain the value for "res". The
existing value of res will be overwritten. */
: "0" (value)); /* Take the contents of "value" and put it
in the same place as parameter #0. */
return res;
}
This may be easier to understand if you read it from the bottom up.

Related

can anyone explain about this XV6 inline asm validateint() test function that uses a pointer as ESP for a system call?

Hi~ I'm working on xv6 and I'm stuck on the validate test in usertests.c. There is asm code and I'm quite confused about what exactly is going on here. Would you like to explain that for me?
// try to crash the kernel by passing in a badly placed integer
void
validateint(int *p)
{
int res;
printf(stdout,"in validateint\n");
asm("mov %%esp, %%ebx\n\t"
"mov %3, %%esp\n\t"
"int %2\n\t"
"mov %%ebx, %%esp" :
"=a" (res) :
"a" (SYS_sleep), "n" (T_SYSCALL), "c" (p) :
"ebx");
printf(stdout,"%d \n",res);
}
I found that res is increasing with p but at some point res becomes 0 and then it becomes -1. The whole function stucks as long as res turn to -1. I have no idea what happened here.
From https://github.com/mit-pdos/xv6-public/blob/eeb7b415dbcb12cc362d0783e41c3d1f44066b17/syscall.c#L10 it appears that system call arguments are passed on the stack. So the purpose of this code seems to be to invoke the system call with a possibly invalid stack, i.e. with the stack pointer containing some random address p.
I'd guess that the return value of 0 corresponds to when the stack is pointing to valid process memory, and -1 is returned when it is not.

Addition function in Windows X86 via inline asm lines in C code

Can someone explain what I'm doing wrong here:
int MachineAdder(int a, int b)
{
int OUT = 0; /* Assign a pointer (&OUT) and write initial data (0) */
__asm ("mov %[dst], %[src]" /* Machine instruction to execute, separated by commas.*/
: [dst] "=r" (OUT)
: [src] "r" (a)
);
__asm ("add %[dst], %[src]" /* Machine instruction to execute, separated by commas.*/
: [dst] "=r" (OUT)
: [src] "r" (b)
);
return OUT; /* Return the value a+b */
}
In my main() function, I call:
printf("0+0 = %d\n", MachineAdder(0,0));
printf("0+1 = %d\n", MachineAdder(0,1));
printf("1+0 = %d\n", MachineAdder(1,0));
printf("1+1 = %d\n", MachineAdder(1,1));
printf("2+1 = %d\n", MachineAdder(2,1));
printf("1+2 = %d\n", MachineAdder(1,2));
In my output, it reads "0 2 0 2 2 4" (whereas I'd expect "0 1 1 2 3 3").
Thanks! Googling answers was messy because some machine instructions seem to be back to front, while others talk about registers but I don't know which register is which or how to use them.
EDIT: Working solution found. There were two errors: src and dst were the wrong way around, and I had never heard of the "+r" string, used for inout parameters. Here's the fixed version:
int MachineAdder(int a, int b)
{
int OUT = 0; /* Assign a pointer (&OUT) and write initial data (0) */
__asm ("mov %[src], %[dst]" /* Machine instruction to execute, separated by commas.*/
: [dst] "=r" (OUT)
: [src] "r" (a)
);
__asm ("add %[src], %[dst]" /* Machine instruction to execute, separated by commas.*/
: [dst] "+r" (OUT)
: [src] "r" (b)
);
return OUT; /* Return the value a+b */
}
Thanks all!
This is because, in the output operands, = mark doesn't guarantee that the location has the existing value while + mark does.
Extended Asm (Using the GNU Compiler Collection (GCC)) says:
Output constraints must begin with either ‘=’ (a variable overwriting an existing value) or ‘+’ (when reading and writing). When using ‘=’, do not assume the location contains the existing value on entry to the asm, except when the operand is tied to an input

How to prevent GCC warning that function has no return when inline assembly?

I'm using a bit of inline assembly to load a function return value into the eax register. However, GCC squawks about the function not returning a value if it is defined as such:
char *trim(char *s);
This generates the following 2 warnings:
control reaches end of non-void function [-Wreturn-type]
No return, in function returning non-void
Hence the use of the weak alias below. Is there a better method to prevent GCC from complaining about no return value from the _trim function? I tried to disable the appropriate compiler warning, but I didn’t have much luck with that.
Here is my code:
// Trim all but digits from the string, return start of string.
void _trim(char *s) {
char *d;
// Save start of string for function return and set d=s.
asm volatile (
"mov %1, %0 \n" // Set d = s.
"push %1" // Save start of string for function return.
: "=r" (d) : "r" (s)
);
// Ignore everything but digits...
while (*s != '\0') {
if (isdigit(*s))
*d++ = *s;
s++;
}
*d = '\0'; // Terminate string.
asm volatile ( "pop %eax" ); // Retrieve beginning of string.
}
// Define weak alias to prevent gcc from squawking about no return value.
char *trim(char *) __attribute__ ((weak, alias ("_trim")));
#endif
int main(void) {
char line[80];
// ...
if (strlen(trim(line)) == 8)
// Do something...
}
Your inline asm is just completely invalid.
You cannot leave an inline asm block with the stack pointer different from what it was when you entered. If you do, any subsequent access to the stack by the compiler will be wrong and all hell will break loose. You can't just "fix it in a later asm block" because you have no way to guarantee that the compiler makes no access to the stack in between. In your own example, you call isdigit in between, making a function call without respecting the function call ABI (that the stack must be aligned mod 16 at function call).
Loading a value into eax (or whatever the ABI's return-value register is) in a particular asm block does not return that value from the function. All it does is clobber a register that you told the compiler you would not clobber (you didn't include it in the clobber list for the asm block), thereby creating another reason all hell could break loose. If the compiler had some important value kept in that register (for example, the stack canary for ssp), and it gets a different value when reading it back, anything could happen. Even ignoring that breakage, there's no reason to think the value you put in eax will still be there when the function returns, or will serve as the function's return value. The compiler may load something else there before it actually returns, or make a transformation (inlining, or various inter-procedural optimizations based on having access to the definition of the function) such that the caller obtains the return value in some other way than what it would use when having made an external call to an unknown function matching the ABI.
The way you fix your code (minimizing changes in style) is:
char *trim(char *s) {
char *d, *d0;
d0 = d = s;
// Ignore everything but digits...
while (*s != '\0') {
if (isdigit(*s))
*d++ = *s;
s++;
}
*d = '\0'; // Terminate string.
return d0;
}

Is it correct to perform a function call like this?

I have an array with 32bit values (nativeParameters with length nativeParameterCount) and a pointer to the function (void* to a cdecl function, here method->nativeFunction) thats supposed to be called. Now I'm trying to do this:
// Push parameters for call
if (nativeParameterCount != 0) {
uint32_t count = 0;
pushParameter:
uint32_t value = nativeParameters[nativeParameterCount - count - 1];
asm("push %0" : : "r"(value));
if (++count < nativeParameterCount) goto pushParameter;
}
// Call method
asm("call *%0" : : "r"(method->nativeFunction));
// Return value
uint32_t eax;
uint32_t edx;
asm("push %eax");
asm("push %edx");
asm("pop %0" : "=r"(edx));
asm("pop %0" : "=r"(eax));
uint64_t returnValue = eax;
// If the typesize of the methods return type is >4 bytes, or with EDX
Type returnType = method->returnType.type;
if (TYPE_SIZES[returnType] > 4) {
returnValue |= (((uint64_t) edx) << 32);
}
// Clean stack
asm("add %%esp, %0" : : "r"(parameterByteSize));
Is this approach suitable to perform a native call (assuming that all target functions accept only 32bit values as parameters)? Can I be sure that it doesn't destroy the stack or mess with registers, or somehow else influence the normal flow? Also, are there other ways of doing this?
Instead of doing this manually yourself, you might want to use the dyncall libary which does all this handling for you.

Errors using inline assembly in C

I'm trying my hand at assembly in order to use vector operations, which I've never really used before, and I'm admittedly having a bit of trouble grasping some of the syntax.
The relevant code is below.
unit16_t asdf[4];
asdf[0] = 1;
asdf[1] = 2;
asdf[2] = 3;
asdf[3] = 4;
uint16_t other = 3;
__asm__("movq %0, %%mm0"
:
: "m" (asdf));
__asm__("pcmpeqw %0, %%mm0"
:
: "r" (other));
__asm__("movq %%mm0, %0" : "=m" (asdf));
printf("%u %u %u %u\n", asdf[0], asdf[1], asdf[2], asdf[3]);
In this simple example, I'm trying to do a 16-bit compare of "3" to each element in the array. I would hope that the output would be "0 0 65535 0". But it won't even assemble.
The first assembly instruction gives me the following error:
error: memory input 0 is not directly addressable
The second instruction gives me a different error:
Error: suffix or operands invalid for `pcmpeqw'
Any help would be appreciated.
You can't use registers directly in gcc asm statements and expect them to match up with anything in other asm statements -- the optimizer moves things around. Instead, you need to declare variables of the appropriate type and use constraints to force those variables into the right kind of register for the instruction(s) you are using.
The relevant constraints for MMX/SSE are x for xmm registers and y for mmx registers. For your example, you can do:
#include <stdint.h>
#include <stdio.h>
typedef union xmmreg {
uint8_t b[16];
uint16_t w[8];
uint32_t d[4];
uint64_t q[2];
} xmmreg;
int main() {
xmmreg v1, v2;
v1.w[0] = 1;
v1.w[1] = 2;
v1.w[2] = 3;
v1.w[3] = 4;
v2.w[0] = v2.w[1] = v2.w[2] = v2.w[3] = 3;
asm("pcmpeqw %1,%0" : "+x"(v1) : "x"(v2));
printf("%u %u %u %u\n", v1.w[0], v1.w[1], v1.w[2], v1.w[3]);
}
Note that you need to explicitly replicate the 3 across all the relevant elements of the second vector.
From intel reference manual:
PCMPEQW mm, mm/m64 Compare packed words in mm/m64 and mm for equality.
PCMPEQW xmm1, xmm2/m128 Compare packed words in xmm2/m128 and xmm1 for equality.
Your pcmpeqw uses an "r" register which is wrong. Only "mm" and "m64" registers
valter
The code above failed when expanding the asm(), it never tried to even assemble anything. In this case, you are trying to use the zeroth argument (%0), but you didn't give any.
Check out the GCC Inline assembler HOWTO, or read the relevant chapter of your local GCC documentation.
He's right, the optimizer is changing register contents. Switching to intrinsics and using volatile to keep things a little more in place might help.

Resources