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 ...
- 11-18-2008 #1
[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); }
- 11-19-2008 #2
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); }
- 11-19-2008 #3
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.
- 11-19-2008 #4
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 %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); }
- 11-19-2008 #5Um, 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.with inline assembler does the programmer always have to tweak the code?
Or maybe I'm not reading your question right.--
Bill
Old age and treachery will overcome youth and skill.
- 11-19-2008 #6
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


