Assembly language parse error before '[' token - c

I get a parse error on line 24(I believe) "parse error before '[' token"
Also, if any of you would like to give me some helpful tips and insights into my project I would appreciate that very much. I'm building a pow function with all calculations done in asm, this piece of code is to change the FPU to round to 0 so that I can split up the exponent into 2 parts (example: 2^3.2 = 2^3 * 2^0.2)
#include <stdio.h>
#include <stdlib.h>
#define PRECISION 3
#define RND_CTL_BIT_SHIFT 10
// floating point rounding modes: IA-32 Manual, Vol. 1, p. 4-20
typedef enum {
ROUND_TOWARD_ZERO = 3 << RND_CTL_BIT_SHIFT
} RoundingMode;
int main(int argc, char **argv)
{
int fpMask = 0x1F9FF;
int localVar = 0x00000;
asm(" FSTCW %[localVarIn] \n" // store FPU control word into localVar
" add %[localVarIn], %[fpMaskOut] \n" // add fpMaskIn to localVar
: [localVarOut] "=m" (localVar)
: [fpMaskOut] "=m" (fpMask)
: [localVarIn] "m" (localVar)
: [fpMaskIn] "m" (localVar)
);
printf("FPU is 0x%08X\n\n", localVar);
return 0;
}

I believe your clobber list is slightly wrong. In GCC, these take the form of the following:
asm("MY ASM CODE" : output0, output1, outputn
: input0, input1, inputn
: clobber0, clobber1, clobbern);
Note that each class is colon-separated (i.e. the set of outputs, the set of inputs etc), then each element within a set is comma-separated. Therefore, try changing your ASM to the following:
asm(" FSTCW %[localVarIn] \n" // store FPU control word into localVar
" add %[localVarIn], %[fpMaskOut] \n" // add fpMaskIn to localVar
: [localVarOut] "=m" (localVar), // Outputs...
[fpMaskOut] "=m" (fpMask)
: [localVarIn] "m" (localVar), // Inputs...
[fpMaskIn] "m" (localVar)

Related

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

Set register using a variable inline assembly

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.

Last stretch of rounding function in ASM

What I essentially have to do is make what is in Main work.
I'm on my last stretch of this assignment (which will likely take just as long as it did for me to get here) I'm having trouble figuring out how to pass the roundingMode that is passed to roundD and using it in ASM.
Also, there is a block of just comments, as far as I can tell, that's all I have left to do. does that sound right?
#include <stdio.h>
#include <stdlib.h>
#define PRECISION 3
#define RND_CTL_BIT_SHIFT 10
// floating point rounding modes: IA-32 Manual, Vol. 1, p. 4-20
typedef enum {
ROUND_NEAREST_EVEN = 0 << RND_CTL_BIT_SHIFT,
ROUND_MINUS_INF = 1 << RND_CTL_BIT_SHIFT,
ROUND_PLUS_INF = 2 << RND_CTL_BIT_SHIFT,
ROUND_TOWARD_ZERO = 3 << RND_CTL_BIT_SHIFT
} RoundingMode;
double roundD(double n, RoundingMode roundingMode)
{
// do not change anything above this comment
int oldCW = 0x0000;
int newCW = 0xF3FF;
int mask = 0x0300;
int tempVar = 0x0000;
asm(" push %eax \n"
" push %ebx \n"
" fstcw %[oldCWOut] \n" //store FPU CW into OldCW
" mov %%eax, %[oldCWOut] \n" //store old FPU CW into tempVar
" mov %[tempVarIn], %%eax \n"
" add %%eax, %[maskIn] \n" //isolate rounding bits
" add %%eax, %[roundModeOut] \n" //adding rounding modifier
//shift in old bits to tempFPU
//do rounding calculation
//store result into n
" fldcw %[oldCWIn] \n" //restoring the FPU CW to normal
" pop %ebx \n"
" pop %eax \n"
: [oldCWOut] "=m" (oldCW),
[newCWOut] "=m" (newCW),
[maskOut] "=m" (mask),
[tempVarOut] "=m" (tempVar),
[roundModeOut] "=m" (roundMode)
: [oldCWIn] "m" (oldCW),
[newCWIn] "m" (newCW),
[maskIn] "m" (mask),
[tempVarIn] "m" (tempVar),
[roundModeIn] "m" (roundMode)
:"eax", "ebx"
);
return n;
// do not change anything below this comment, except for printing out your name
}
int main(int argc, char **argv)
{
double n = 0.0;
if (argc > 1)
n = atof(argv[1]);
printf("roundD even %.*f = %.*f\n",
PRECISION, n, PRECISION, roundD(n, ROUND_NEAREST_EVEN));
printf("roundD down %.*f = %.*f\n",
PRECISION, n, PRECISION, roundD(n, ROUND_MINUS_INF));
printf("roundD up %.*f = %.*f\n",
PRECISION, n, PRECISION, roundD(n, ROUND_PLUS_INF));
printf("roundD zero %.*f = %.*f\n",
PRECISION, n, PRECISION, roundD(n, ROUND_TOWARD_ZERO));
return 0;
}
While C might like to pretend that enum is not just an integer, it is just an integer. If you can't use roundingMode directly in the assembly, create an integer local variable and set it equal to the roundingMode parameter.
I'm just offering this as a suggestion to you. I've never used inline assembly before and I've never used x86 assembly before, but if all you need to do is reference the parameter, what I said above should work.

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.

How do I retrieve the number of processors on C / Linux?

I am writing a small C application that use some threads for processing data. I want to be able to know the number of processors on a certain machine, without using system() & in combination to a small script.
The only way i can think of is to parse /proc/cpuinfo. Any other useful suggestions ?
As others have mentioned in comments, this answer is useful:
numCPU = sysconf( _SC_NPROCESSORS_ONLN );
Leaving as a solution for folks that might skip over comments...
Why not use sys/sysinfo.h?
#include <sys/sysinfo.h>
#include <stdio.h>
void main () {
printf ("You have %d processors.\n", get_nprocs ());
}
Way more information can be found on the man page
$ man 3 get_nprocs
machine:/sys/devices/system/cpu$ ls
cpu0 cpu3 cpu6 kernel_max perf_counters sched_mc_power_savings
cpu1 cpu4 cpu7 offline possible
cpu2 cpu5 cpuidle online present
If you have a machine with sysfs, take a look in /sys/devices/system/cpu.
Make sure you're asking for what you want -- CPUs, cores, hyperthreads, etc.
The following was the code that I used to figure number of cores.....it might help you
//Finding the number of cores(logical processor) using cpuid instruction.....
__asm
{
mov eax,01h //01h is for getting number of cores present in the processor
cpuid
mov t,ebx
}
(t>>16)&0xff contains the number cores........
I guess this could help you
http://lists.gnu.org/archive/html/autoconf/2002-08/msg00126.html
#include <stdio.h>
void getPSN(char *PSN)
{int varEAX, varEBX, varECX, varEDX;
char str[9];
//%eax=1 gives most significant 32 bits in eax
__asm__ __volatile__ ("cpuid": "=a" (varEAX), "=b" (varEBX), "=c" (varECX), "=d" (varEDX) : "a" (1));
sprintf(str, "%08X", varEAX); //i.e. XXXX-XXXX-xxxx-xxxx-xxxx-xxxx
sprintf(PSN, "%C%C%C%C-%C%C%C%C", str[0], str[1], str[2], str[3], str[4], str[5], str[6], str[7]);
//%eax=3 gives least significant 64 bits in edx and ecx [if PN is enabled]
__asm__ __volatile__ ("cpuid": "=a" (varEAX), "=b" (varEBX), "=c" (varECX), "=d" (varEDX) : "a" (3));
sprintf(str, "%08X", varEDX); //i.e. xxxx-xxxx-XXXX-XXXX-xxxx-xxxx
sprintf(PSN, "%s-%C%C%C%C-%C%C%C%C", PSN, str[0], str[1], str[2], str[3], str[4], str[5], str[6], str[7]);
sprintf(str, "%08X", varECX); //i.e. xxxx-xxxx-xxxx-xxxx-XXXX-XXXX
sprintf(PSN, "%s-%C%C%C%C-%C%C%C%C", PSN, str[0], str[1], str[2], str[3], str[4], str[5], str[6], str[7]);
}
int main()
{
char PSN[30]; //24 Hex digits, 5 '-' separators, and a '\0'
getPSN(PSN);
printf("%s\n", PSN); //compare with: lshw | grep serial:
return 0;
}
Here's a minimal example of how to get physical cores and virtual threads:
#include <stdio.h>
...
unsigned int thread_count, core_count;
FILE *cpu_info = fopen("/proc/cpuinfo", "r");
while (!fscanf(cpu_info, "siblings\t: %u", &thread_count))
fscanf(cpu_info, "%*[^s]");
while (!fscanf(cpu_info, "cpu cores\t: %u", &core_count))
fscanf(cpu_info, "%*[^c]");
fclose(cpu_info);
It's more portable than _SC_NPROCESSORS_ONLN as it doesn't require glibc extensions.
Note that you don't need to check for EOF in this example as fscanf will return EOF if reached. This will cause the loop to stop safely.
Also, this example doesn't contain error checking to see if fopen failed. This should be done however you see fit.
This fscanf technique was derived from here: https://stackoverflow.com/a/43483850

Resources