Find the answer to your Linux question:
Results 1 to 6 of 6
Note this will only run on a AMD 64 bit machine(and maybe an intel 64 bit) basically the function void setit(importsetx setx, int intval) will work if I call fprintf ...
  1. #1
    Linux Enthusiast gerard4143's Avatar
    Join Date
    Dec 2007
    Location
    Canada, Prince Edward Island
    Posts
    714

    [SOLVED] Inline assembler question

    Note this will only run on a AMD 64 bit machine(and maybe an intel 64 bit)

    basically the function void setit(importsetx setx, int intval) will work if I call fprintf within it...as soon as I
    remove the fprintf it fails with segmentation fault. Any suggestions as to why this is happening...Gerard4143

    Note the inline assembly code does work, I remmed out the original inline below and it worked with no problems

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    #include <fcntl.h>
    #include <sys/mman.h>
    
    typedef int (*importgetx)();
    typedef void (*importsetx)(int);
    
    //this is the function********************
    
    void setit(importsetx setx, int intval)
    {
    	__asm__("pushq	%1\n\t"
    		"call	*%0\n\t"
    		"popq	%%rax\n\t"
    		:"=m"(setx), "=m"(intval)
    		);
    	fprintf(stdout, "setx->%p\n", setx);	//if I remove this line the function will fail 
    						//with a segmentation fault******************
    }					
    
    //******************************************
    
    int main(int argc, char**argv)
    {
    	importgetx GetX;
    	importsetx SetX;
    	
    	int choice, val;
    	char *ch;
    
    	int fd = 0;
    
    	char assemcode[] = 	{						//getx()
    					0x55,					//pushq   %rbp
    					0x48,0x89,0xe5,				//movq    %rsp,%rbp
    					0x48,0x8b,0x05,0x19,0x00,0x00,0x00,	//movq    0x19(%rip),%rax
    					0x48,0x89,0xec,				//movq    %rbp,%rsp
    					0x5d,					//popq    %rbp	
    					0xc3,//16				//retq
    	
    										//setx(int val)
    					0x55,					//pushq   %rbp
    					0x48,0x89,0xe5,				//movq    %rsp,%rbp
    					0x48,0x8b,0x45,0x10,			//movq    0x10(%rbp),%rax
    					0x48,0x89,0x05,0x05,0x00,0x00,0x00,	//movq    %rax,0x5(%rip)
    					0x48,0x89,0xec,				//movq    %rbp,%rsp
    					0x5d,					//popq    %rbp
    					0xc3,//20				//retq
    
    					0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00	//8 //mydata: .quad 0			
    				};
    
    	fd = open("gerard", O_RDWR|O_CREAT);
    	if (fd < 1)
    	{
    		fputs("could not open gerard!\n", stderr);
    		exit(EXIT_FAILURE);
    	}
    
    	write(fd, assemcode, 44);
    
    	GetX = (importgetx)mmap(0, 44, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED, fd, 0);
    	ch = (char*)GetX;
    	SetX = (importsetx)(ch + 16);
    
    	while (true)
    	{
    		fputs("(0)exit (1)view (2)set->", stdout);
    		fscanf(stdin, "%d", &choice);
    
    		if (choice == 0) break;
    
    		if (choice == 1)
    		{
    			fprintf(stdout, "ans->%d\n", GetX());
    		}
    
    		if (choice == 2)
    		{
    			fputs("enter a number->", stdout);
    			fscanf(stdin, "%d", &val);
    			setit(SetX, val);		//****this is the function call to replace the inline code
    
    			//__asm__("pushq %1\n\t"  	//****if I call the inline here no problems****
    			//	"call	*%0\n\t"	//****this is the original inline call
    			//	"popq	%%rax\n\t"
    			//	:"=m"(SetX), "=m"(val)
    			//	);
    		}
    
    	}
    
    	close(fd);
    	exit(EXIT_SUCCESS);
    }

  2. #2
    Linux Enthusiast gerard4143's Avatar
    Join Date
    Dec 2007
    Location
    Canada, Prince Edward Island
    Posts
    714

    The ugliest solution in the world

    I replaced the function with a macro an all my problems when away....

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    #include <fcntl.h>
    #include <sys/mman.h>
    
    typedef int (*importgetx)();
    typedef void (*importsetx)(int);
    
    //the macro that replaced the setit function
    
    #define setit(x, y) ({ 	\
    			__asm__("pushq	%1\n\t" \
    				"call	*%0\n\t" \
    				"popq	%%rax\n\t" \
    				:"=m"(x), "=m"(y) \
    				);})
    
    //the macro that replaced the setit function
    
    int main(int argc, char**argv)
    {
    	unlink("gerard");
    	importgetx GetX;
    	importsetx SetX;
    	
    	int choice, val;
    	char *ch;
    
    	int fd = 0;
    
    	char assemcode[] = 	{						//getx()
    					0x55,					//pushq   %rbp
    					0x48,0x89,0xe5,				//movq    %rsp,%rbp
    					0x48,0x8b,0x05,0x19,0x00,0x00,0x00,	//movq    0x19(%rip),%rax
    					0x48,0x89,0xec,				//movq    %rbp,%rsp
    					0x5d,					//popq    %rbp	
    					0xc3,//16				//retq
    	
    										//setx(int val)
    					0x55,					//pushq   %rbp
    					0x48,0x89,0xe5,				//movq    %rsp,%rbp
    					0x48,0x8b,0x45,0x10,			//movq    0x10(%rbp),%rax
    					0x48,0x89,0x05,0x05,0x00,0x00,0x00,	//movq    %rax,0x5(%rip)
    					0x48,0x89,0xec,				//movq    %rbp,%rsp
    					0x5d,					//popq    %rbp
    					0xc3,//20				//retq
    
    					0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00	//8 //mydata: .quad 0			
    				};
    
    	fd = open("gerard", O_RDWR|O_CREAT);
    	if (fd < 1)
    	{
    		fputs("could not open gerard!\n", stderr);
    		exit(EXIT_FAILURE);
    	}
    
    	write(fd, assemcode, 44);
    
    	GetX = (importgetx)mmap(0, 44, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED, fd, 0);
    	ch = (char*)GetX;
    	SetX = (importsetx)(ch + 16);
    
    	while (true)
    	{
    		fputs("(0)exit (1)view (2)set->", stdout);
    		fscanf(stdin, "%d", &choice);
    
    		if (choice == 0) break;
    
    		if (choice == 1)
    		{
    			fprintf(stdout, "ans->%d\n", GetX());
    		}
    
    		if (choice == 2)
    		{
    			fputs("enter a number->", stdout);
    			fscanf(stdin, "%d", &val);
    			setit(SetX, val);		
    		}
    
    	}
    
    	close(fd);
    	exit(EXIT_SUCCESS);
    }

  3. #3
    Linux Engineer wje_lf's Avatar
    Join Date
    Sep 2007
    Location
    Mariposa
    Posts
    1,192
    I have no experience with assembly language programming under Linux, so the following will be a little vague.

    My guess is that there's more going on in function call and return than you realize. I could be wrong, but here's my two cents' worth.

    For purposes of exploration, make sure you do all compiling with optimization turned off (-O0). This is the default, but it can't hurt to include this option.

    Take your original source, with the fprintf() statement, compile it with the -S flag, and look at the assembly language source. Then do the same without the fprintf() statement. Might it be that the compiler includes some necessary returning code in the first of these, but not with the second, so that in the second example you need to do something explicit about adjusting stack frames or whatever?

    Just for kicks and grins, also try compiling the following program. Then look carefully at the code generated for function xxx(), and make sure you understand why each instruction is generated.

    Again, I'm guessing that your original code with the fprintf() caused the proper code to be generated for returning from a function, and that with the fprintf() call removed, it would be necessary you to include at least some of that returning code explicitly.
    Code:
    volatile int alpha;
    volatile int beta;
    
    void xxx(int gamma)
    {
      volatile int delta;
    
      delta=gamma;
      beta=delta;
    }
    
    int main(void)
    {
      alpha=5;
      xxx(alpha);
    
      return 0;
    }
    --
    Bill

    Old age and treachery will overcome youth and skill.

  4. #4
    Linux Enthusiast gerard4143's Avatar
    Join Date
    Dec 2007
    Location
    Canada, Prince Edward Island
    Posts
    714

    Got it working

    Note code will only work on a AMD 64 machine(or maybe a intel 64 bit)

    Bill I read the assembled code and found that the function call setit was using the regs &#37;rsi, %rdi to pass its values.
    So I called the regs directly in setit and everything works correctly...
    Question, with inline assembler does the programmer always have to tweak the code? From this simple example
    I would have to yes but I use inline so infrequently that this is just an opinion...
    Thanks for your reply and help Bill...and I'm checking out your volatile example.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    #include <fcntl.h>
    #include <sys/mman.h>
    
    typedef int (*importgetx)();
    typedef void (*importsetx)(int);
    
    //this is the function********************
    
    void setit(importsetx setx,long intval)
    {					//if I skip the stack and call the regs that the
    					//values are pass in everything works...
    	__asm__ ("pushq	%%rsi\n\t"	//the assembled code uses rsi reg to pass intval
    		"call	*%%rdi\n\t"	//the assembled ode uses rdi reg to pass setx
    		"popq	%%rsi\n\t"
    		:
    		);
    }					
    
    //******************************************
    
    int main(int argc, char**argv)
    {
    	unlink("gerard");
    	importgetx GetX;
    	importsetx SetX;
    	
    	long choice, val;
    	char *ch;
    
    	int fd = 0;
    
    	char assemcode[] = 	{						//getx()
    					0x55,					//pushq   %rbp
    					0x48,0x89,0xe5,				//movq    %rsp,%rbp
    					0x48,0x8b,0x05,0x19,0x00,0x00,0x00,	//movq    0x19(%rip),%rax
    					0x48,0x89,0xec,				//movq    %rbp,%rsp
    					0x5d,					//popq    %rbp	
    					0xc3,//16				//retq
    	
    										//setx(int val)
    					0x55,					//pushq   %rbp
    					0x48,0x89,0xe5,				//movq    %rsp,%rbp
    					0x48,0x8b,0x45,0x10,			//movq    0x10(%rbp),%rax
    					0x48,0x89,0x05,0x05,0x00,0x00,0x00,	//movq    %rax,0x5(%rip)
    					0x48,0x89,0xec,				//movq    %rbp,%rsp
    					0x5d,					//popq    %rbp
    					0xc3,//20				//retq
    
    					0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00	//8 //mydata: .quad 0			
    				};
    
    	fd = open("gerard", O_RDWR|O_CREAT);
    	if (fd < 1)
    	{
    		fputs("could not open gerard!\n", stderr);
    		exit(EXIT_FAILURE);
    	}
    
    	write(fd, assemcode, 44);
    
    	GetX = (importgetx)mmap(0, 44, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED, fd, 0);
    	ch = (char*)GetX;
    	SetX = (importsetx)(ch + 16);
    
    	while (true)
    	{
    		fputs("(0)exit (1)view (2)set->", stdout);
    		fscanf(stdin, "%d", &choice);
    
    		if (choice == 0) break;
    
    		if (choice == 1)
    		{
    			fprintf(stdout, "ans->%d\n", GetX());
    		}
    
    		if (choice == 2)
    		{
    			fputs("enter a number->", stdout);
    			fscanf(stdin, "%d", &val);
    			setit(SetX, val);		//****this is the function call to replace the inline code
    
    			//__asm__("pushq %1\n\t"  	//****if I call the inline here no problems****
    			//	"call	*%0\n\t"	//****this is the original inline call
    			//	"popq	%%rax\n\t"
    			//	:"=m"(SetX), "=m"(val)
    			//	);
    		}
    
    	}
    
    	close(fd);
    	exit(EXIT_SUCCESS);
    }

  5. #5
    Linux Engineer wje_lf's Avatar
    Join Date
    Sep 2007
    Location
    Mariposa
    Posts
    1,192
    with inline assembler does the programmer always have to tweak the code?
    Um, probably not, because inline assembler worked for you, right? The only problem you had was when you isolated the code into a separate function, and if I read your new post correctly, that even works now.

    Or maybe I'm not reading your question right.
    --
    Bill

    Old age and treachery will overcome youth and skill.

  6. #6
    Linux Enthusiast gerard4143's Avatar
    Join Date
    Dec 2007
    Location
    Canada, Prince Edward Island
    Posts
    714
    Bill I moved the inline assembler code inside a function so it would be easier to call,
    I guess you could call it a C wrapper around the inline code.

    Anyway looking at the solutions I presented here, I think, I would choose
    the macro solution...to me its cleaner(thou uglier)...Thanks again Bill...Gerard4143

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
...