"undefined named operand" error in C assembly - c

I'm trying to create a function using assembly like so :
void asm_loop ( int n ){
register int *p1 asm ("r2") = &n;
asm goto (
" cmp r2 , #0 \n\t" // Compare n to "0"
" beq %l[ stop]" // Abort if n=0
:
: [ num_repeats ] "r" ( p1 )
:
:stop);
stop:
return ;
}
I have the following error and don't understand why :
error: undefined named operand ' stop '
I use gcc version upper than 4.5 so "asm goto" is included.
Does anyone have an idea on how to fix this? As it's a label i don't understand how i can define it.
Thank you in advance.
I tried searching for more information on https://gcc.gnu.org/onlinedocs/gcc-7.5.0/gcc/Extended-Asm.html#Extended-Asm.
But they seem to use this function the same way as I do :
int frob(int x)
{
int y;
asm goto ("frob %%r5, %1; jc %l[error]; mov (%2), %%r5"
: /* No outputs. */
: "r"(x), "r"(&y)
: "r5", "memory"
: error);
return y;
error:
return -1;
}

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

Assembly loop through a string to count characters

i try to make an assembly code that count how many characters is in the string, but i get an error.
Code, I use gcc and intel_syntax
#include <stdio.h>
int main(){
char *s = "aqr b qabxx xryc pqr";
int x;
asm volatile (
".intel_syntax noprefix;"
"mov eax, %1;"
"xor ebx,ebx;"
"loop:"
"mov al,[eax];"
"or al, al;"
"jz print;"
"inc ebx;"
"jmp loop"
"print:"
"mov %0, ebx;"
".att_syntax prefix;"
: "=r" (x)
: "r" (s)
: "eax", "ebx"
);
printf("Length of string: %d\n", x);
return 0;
}
And i got error:
Error: invalid use of register
Finally I want to make program, which search for regex pattern([pq][^a]+a) and prints it's start position and length. I wrote it in C, but I have to make it work in assembly:
My C code:
#include <stdio.h>
#include <string.h>
int main(){
char *s = "aqr b qabxx xryc pqr";
int y,i;
int x=-1,length=0, pos = 0;
int len = strlen(s);
for(i=0; i<len;i++){
if((s[i] == 'p' || s[i] == 'q') && length<=0){
pos = i;
length++;
continue;
} else if((s[i] != 'a')) && pos>0){
length++;
} else if((s[i] == 'a') && pos>0){
length++;
if(y < length) {
y=length;
length = 0;
x = pos;
pos = 0;
}
else
length = 0;
pos = 0;
}
}
printf("position: %d, length: %d", x, y);
return 0;
}
You omitted the semicolon after jmp loop and print:.
Also your asm isn't going to work correctly. You move the pointer to s into eax, but then you overwrite it with mov al,[eax]. So the next pass thru the loop, eax doesn't point to the string anymore.
And when you fix that, you need to think about the fact that each pass thru the loop needs to change eax to point to the next character, otherwise mov al,[eax] keeps reading the same character.
Since you haven't accepted an answer yet (by clicking the checkmark to the left), there's still time for one more edit.
Normally I don't "do people's homework", but it's been a few days. Presumably the due date for the assignment has passed. Such being the case, here are a few solutions, both for the education of the OP and for future SO users:
1) Following the (somewhat odd) limitations of the assignment:
asm volatile (
".intel_syntax noprefix;"
"mov eax, %1;"
"xor ebx,ebx;"
"cmp byte ptr[eax], 0;"
"jz print;"
"loop:"
"inc ebx;"
"inc eax;"
"cmp byte ptr[eax], 0;"
"jnz loop;"
"print:"
"mov %0, ebx;"
".att_syntax prefix;"
: "=r" (x)
: "r" (s)
: "eax", "ebx"
);
2) Violating some of the assignment rules to make slightly better code:
asm (
"\n.intel_syntax noprefix\n\t"
"mov eax, %1\n\t"
"xor %0,%0\n\t"
"cmp byte ptr[eax], 0\n\t"
"jz print\n"
"loop:\n\t"
"inc %0\n\t"
"inc eax\n\t"
"cmp byte ptr[eax], 0\n\t"
"jnz loop\n"
"print:\n"
".att_syntax prefix"
: "=r" (x)
: "r" (s)
: "eax", "cc", "memory"
);
This uses 1 fewer register (no ebx) and omits the (unnecessary) volatile qualifier. It also adds the "cc" clobber to indicate that the code modifies the flags, and uses the "memory" clobber to ensure that any 'pending' writes to s get flushed to memory before executing the asm. It also uses formatting (\n\t) so the output from building with -S is readable.
3) Advanced version which uses even fewer registers (no eax), checks to ensure that s is not NULL (returns -1), uses symbolic names and assumes -masm=intel which results in more readable code:
__asm__ (
"test %[string], %[string]\n\t"
"jz print\n"
"loop:\n\t"
"inc %[length]\n\t"
"cmp byte ptr[%[string] + %[length]], 0\n\t"
"jnz loop\n"
"print:"
: [length] "=r" (x)
: [string] "r" (s), "[length]" (-1)
: "cc", "memory"
);
Getting rid of the (arbitrary and not well thought out) assignment constraints allows us to reduce this to 7 lines (5 if we don't check for NULL, 3 if we don't count labels [which aren't actually instructions]).
There are ways to improve this even further (using %= on the labels to avoid possible duplicate symbol issues, using local labels (.L), even writing it so it works for both -masm=intel and -masm=att, etc.), but I daresay that any of these 3 are better than the code in the original question.
Well Kuba, I'm not sure what more you are after here before you'll accept an answer. Still, it does give me the chance to include Peter's version.
4) Pointer increment:
__asm__ (
"cmp byte ptr[%[string]], 0\n\t"
"jz .Lprint%=\n"
".Loop%=:\n\t"
"inc %[length]\n\t"
"cmp byte ptr[%[length]], 0\n\t"
"jnz .Loop%=\n"
".Lprint%=:\n\t"
"sub %[length], %[string]"
: [length] "=&r" (x)
: [string] "r" (s), "[length]" (s)
: "cc", "memory"
);
This does not do the 'NULL pointer' check from #3, but it does do the 'pointer increment' that Peter was recommending. It also avoids potential duplicate symbols (using %=), and uses 'local' labels (ones that start with .L) to avoid extra symbols getting written to the object file.
From a "performance" point of view, this might be slightly better (I haven't timed it). However from a "school project" point of view, the clarity of #3 seems like it would be a better choice. From a "what would I write in the real world if for some bizarre reason I HAD to write this in asm instead of just using a standard c function" point of view, I'd probably look at usage, and unless this was performance critical, I'd be tempted to go with #3 in order to ease future maintenance.

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.

Using Inline Assembly to update internal system registers

I'm tying to use inline assembly in a project that i'm currently working on. The project is about building a simple OS from scratch.
I've made it to the part where i begin writing the kernel code and the screen driver.
The problem is in the screen driver and i think it is exactly in the code which saves/retrieves the screen cursor (the blinking one) into/from internal registers.
This is where inline assembly is used in my code.
I have separated the inline assembly part from the screen driver in a separate file in order to test it's functionality properly.
Here is the test.c :
# include <stdio.h>
// scree device I/O ports
# define REG_SCREEN_CTRL 0x3D4
# define REG_SCREEN_DATA 0x3D5
unsigned char port_byte_in ( unsigned short port ) {
// A handy C wrapper function that reads a byte from the specified port
// "= a " ( result ) means : put AL register in variable RESULT when finished
// " d " ( port ) means : load EDX with port
unsigned char result ;
__asm__ ("in %%dx, %%al" : "=a" (result) : "d" (port));
return result ;
}
void port_byte_out ( unsigned short port , unsigned char data ) {
// " a " ( data ) means : load EAX with data
// " d " ( port ) means : load EDX with port
__asm__ ("out %%al, %%dx" : :"a" (data) , "d" (port));
}
unsigned short port_word_in ( unsigned short port ) {
unsigned short result ;
__asm__ ("in %%dx, %%ax" : "=a" (result) : "d" (port));
return result ;
}
void port_word_out ( unsigned short port , unsigned short data ) {
__asm__ ("out %%ax, %%dx" : :"a" (data) , "d" (port));
}
void main (){
int i = 10;
printf("%d\n",i);
port_byte_out ( REG_SCREEN_CTRL , 14);
port_byte_out ( REG_SCREEN_DATA , ( unsigned char )( i >> 8));
port_byte_out ( REG_SCREEN_CTRL , 15);
port_byte_out ( REG_SCREEN_CTRL , 14);
int j = port_byte_in ( REG_SCREEN_DATA ) << 8;
printf("%d\n",j);
port_byte_out ( REG_SCREEN_CTRL , 15);
j += port_byte_in ( REG_SCREEN_DATA );
printf("%d\n",j);
}
by running test.c it gives me :
10
Segmentation fault (core dumped)
i was expecting some value rather than a segmentation fault.
Any help would be greatly appreciated , Thanks.
The IN and OUT instructions are privileged. You cannot generally call them from a user-space executable in Linux.
You can use the ioperm() or iopl() system calls to give your executable the right to access I/O ports directly. Note that these system calls both require your executable to be running as root.

How do you detect the CPU architecture type during run-time with GCC and inline asm?

I need to find the architecture type of a CPU. I do not have access to /proc/cpuinfo, as the machine is running syslinux. I know there is a way to do it with inline ASM, however I believe my syntax is incorrect as my variable iedx is not being set properly.
I'm drudging along with ASM, and by no means an expert. If anyone has any tips or can point me in the right direction, I would be much obliged.
static int is64Bit(void) {
int iedx = 0;
asm("mov %eax, 0x80000001");
asm("cpuid");
asm("mov %0, %%eax" : : "a" (iedx));
if ((iedx) && (1 << 29))
{
return 1;
}
return 0;
}
How many bugs can you fit in so few lines ;)
Try
static int is64bit(void) {
int iedx = 0;
asm volatile ("movl $0x80000001, %%eax\n"
"cpuid\n"
: "=d"(iedx)
: /* No Inputs */
: "eax", "ebx", "ecx"
);
if(iedx & (1 << 29))
{
return 1;
}
return 0;
}

Resources