I am trying to write an inline assebly function which exchanges two values.( and i'm using extended ASM format)
This code works:
#include <stdio.h>
void Exchange(int *x, int *y)
{
printf("In Exchange function: Before exchange x is: %d\n",*x);
printf("In Exchange function: Before exchange y is: %d\n",*y);
asm("xchg %%eax,%%edx\n\t" \
:"+a"(*x),"+d"(*y));
printf("In Exchange function: After exchange x is: %d\n",*x);
printf("In Exchange function: After exchange y is: %d\n",*y);
}
int main()
{
int x=20;
int y=30;
printf("In main: Before exchange x is: %d\n",x);
printf("In main: Before exchange y is: %d\n",y);
Exchange(&x,&y);
printf("In main: After exchange x is: %d\n",x);
printf("In main: After exchange y is: %d\n",y);
return 0;
}
but when i try to wirte it in full assembly like below i get segmentation fault (core dumped) error.
void Exchange(int *x, int *y)
{
asm("subl $8,%%esp\n\t" \
"movl %%eax,4(%%esp)\n\t" \
"movl %%edx,(%%esp)\n\t" \
"call printf\n\t" \
"addl $8,%%esp\n\t" \
"xchg %%eax,%%edx\n\t" \
"subl $8,%%esp\n\t" \
"movl %%eax,4(%%esp)\n\t" \
"movl %%edx,(%%esp)\n\t" \
"call printf\n\t" \
"addl $8,%%esp\n\t" \
:"+a"(*x),"+d"(*y));
}
int main()
{
int x=20;
int y=30;
printf("In main: Before exchange x is: %d\n",x);
printf("In main: Before exchange y is: %d\n",y);
Exchange(&x,&y);
printf("In main: After exchange x is: %d\n",x);
printf("In main: After exchange y is: %d\n",y);
return 0;
}
Aren't we allowed to use printf function in the assembly section?
Your asm code calls printf with two integer arguments -- no format string. So it tries to dereference the first integer as a pointer to a format string and crashes.
Also, calling printf will clobber the values in %eax and %edx, as they are not preserved across calls in the standard x86 calling conventions.
Related
I want to forward args of variadic function, I have already find the some topic.
Forward an invocation of a variadic function in C
When I start to practice, I found a problem.
#include <stdio.h>
#include <stdarg.h>
void fun1(const char *msg, ...) // try to forward printf
{
va_list arg_list;
va_start(arg_list, msg);
vprintf(msg, arg_list);
va_end(arg_list);
}
void fun2(const char *msg, ...) // try to forward fun1
{
va_list arg_list;
va_start(arg_list, msg);
fun1(msg, arg_list);
va_end(arg_list);
}
int main()
{
fun1("this is int %d, float %f\n", 1, 2.3);
fun2("this is int %d, float %f\n", 1, 2.3);
return 0;
}
I compile code with gcc main.c and the output shown that
this is int 1, float 2.300000
this is int 6684168, float 2.300000
I can not understand why the fun2 not forward the args of fun1 correctly.
Why the int 1 goes to another number but 2.3 still good.
How can I modify my code to implement the forward?
Thanks for your time.
fun1 needs a list of arguments to match its format, but when call it from fun2 you give it a va_list. To call it that way you need to rewrite it to take a va_list rather than a ...:
void fun1(const char *fmt, va_list args) {
vfprintf(fmt, args);
}
If you're using gcc, you can avoid many problems of this nature by using -Wall and adding a declaration for your functions that take ...:
extern void fun2(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
This tells gcc that fun2 takes printf-style arguments starting from the second argument with the first argument as the format. With this, it will warn you if the arguments passed to fun1 don't match the format string.
As suggtested by StoryTeller - Unslander Monica and Chris Dodd, My finial code looks like follows.
// before modify
// vprintf <-- fun1 <-- fun2
// after modify
// vprintf <-- vfun1 <--- fun1
// |- fun2
#include <stdio.h>
#include <stdarg.h>
void vfun1(const char *msg, va_list arg_list)
{
printf("this is vfun1\n");
vprintf(msg, arg_list);
}
void fun1(const char *msg, ...) // try to forward vprintf, but implemented by call vfun1
{
printf("this is fun1\n");
va_list arg_list;
va_start(arg_list, msg);
vfun1(msg, arg_list);
va_end(arg_list);
}
void fun2(const char *msg, ...) // try to forward fun1, but implemented by call vfun1
{
printf("this is fun2\n");
va_list arg_list;
va_start(arg_list, msg);
vfun1(msg, arg_list);
va_end(arg_list);
}
int main()
{
printf("------------------------------------\n");
fun1("this is int %d, float %f\n", 5, 2.3);
printf("------------------------------------\n");
fun2("this is int %d, float %f\n", 5, 2.3);
return 0;
}
I have a basic bootloader in c, but when I try to pass a parameter to a function, it doesn't work quite right.
The following code doesn't work:
__asm__(".code16\n");
__asm__("call main\n");
void main(){
putchar('X');
while(1){}
}
void putchar(char c){
__asm__("movb %0, %%al\n" : : "r"(c));
__asm__("movb $0x0e, %ah\n");
__asm__("int $0x10\n");
}
It should print out an X, but instead it just moves the cursor forward as if printing a space.
The following code works because it doesn't pass the character as a parameter:
__asm__(".code16\n");
__asm__("call main\n");
char c;
void main(){
c = 'X';
putchar();
while(1){}
}
void putchar(){
__asm__("movb %0, %%al\n" : : "r"(c));
__asm__("movb $0x0e, %ah\n");
__asm__("int $0x10\n");
}
Can someone explain why it isn't working?
The problem wasn't the fact that it was being passed as a parameter, but rather, I was using the assembly wrongly. The following code works:
__asm__(".code16\n");
__asm__("call main\n");
void main(){
putchar('!');
while(1){}
}
void putchar(char c){
__asm__ __volatile__("int $0x10" : : "a"(0x0e00 | c), "b"(0x0007));
}
I've built a short program written on C and inline assembly on my linux x86_64. It is supposed to write a string to stdout. I found it in an article on the internet:
int write_call( int fd, const char * str, int len ){
long __res;
__asm__ volatile ( "int $0x80":
"=a" (__res):"0"(__NR_write),"b"((long)(fd)),"c"((long)(str)),"d"((long)(len)) );
return (int) __res;
}
void do_write( void ){
char * str = "Paragon output string.\n";
int len = strlen( str ), n;
printf( "string for write length = %d\n", len );
n = write_call( 1, str, len );
printf( "write return : %d\n", n );
}
int main( int argc, char * argv[] ){
do_write();
return EXIT_SUCCESS;
}
But as I run it, it works incorrectly, making output
"write return : -14"
If I build and run it on 32-bit linux it does what is expected.
After some research I fount out that instruction "int $0x80" is a x86 instruction and truncates arguments in registers if called on x86_64.
But I couldn't find a proper substitution of "int $0x80" for x86_64 architecture. I have zero experience in assembly.
What should I put instead of "int $0x80" to receive expected result?
For amd64, you need to use "syscall" - and use different registers - instead of "int 0x80":
http://cs.lmu.edu/~ray/notes/linuxsyscalls/
http://blog.rchapman.org/post/36801038863/linux-system-call-table-for-x86-64
http://crypto.stanford.edu/~blynn/rop/
Here's a good example:
How to invoke a system call via sysenter in inline assembly (x86/amd64 linux)?
#include <unistd.h>
int main(void)
{
const char hello[] = "Hello World!\n";
const size_t hello_size = sizeof(hello);
ssize_t ret;
asm volatile
(
"movl $1, %%eax\n\t"
"movl $1, %%edi\n\t"
"movq %1, %%rsi\n\t"
"movl %2, %%edx\n\t"
"syscall"
: "=a"(ret)
: "g"(hello), "g"(hello_size)
: "%rdi", "%rsi", "%rdx", "%rcx", "%r11"
);
return 0;
I've following declarations:
typedef void (*foo)(int op, int arg1, int arg2);
void goo(foo f);
{
BODY;
}
and I want to store function f passed to goo in my code but the natural way of modifying body and adding global foo variable (I cannot change definition of goo but I'm able to edit body):
foo _f;
void goo(foo f);
{
_f = f;
}
is making segfaults. I'd be grateful for any hints.
edit
Based on your full code, you should change the name of your function callback() in test.c to something other than "callback" as you already defined the symbol in pagesim.c. I made this edit and the program ran fine.
Here is a test that compiles and runs, maybe you can spot your error based on this:
#include <stdio.h>
typedef void (*foo)(int op, int arg1, int arg2);
foo _f;
void goo(foo f)
{
_f = f;
_f(1, 2, 3);
}
void testfxn(int op, int arg1, int arg2) {
printf("%d %d %d", op, arg1, arg2);
}
void main() {
goo(testfxn);
}
From the code you pasted, where is you actual function definition of type
void func(int op, int arg1, int arg2)
The segment fault is from goo(), you see output from printf(), but the following call of callback2() generate segment fault. callback2 is a function pointer, but it doesn't point to any actual function.
you should define a function
void func(int op, int arg1, int arg2)
{
printf("%d %d %d\n", op, arg1, arg2);
}
then you call goo() and page_sim_init() as
goo(func);
page_sim_init(page_size, mem_size, addr_space_size,
strategy, max_concurrent_operations, func);
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
If I have a function
int foo() {
/* stuff */
}
to which I want to send arguments (in spite the fact that it's a bad practice):
int main(void) {
int arg1 = 3;
int arg2 = 4;
foo(arg1, arg2);
return 0;
}
then, how can I refer to the arguments arg1 and arg2 inside foo()?
What's wrong with int foo(int arg1, int arg2);?
If you're unsure about the number of arguments you will be passing look into variadic functions.
This is not exactly what you want and is completely unportable but it illustrates
the principle. You probably have to adjust the offsets and the offsets will be different if the calling function (main in this case) has other variables on the stack.
And of course, if the target platform has a stack that grows in the other direction you'd have to change the loop to count down p instead.
#include <stdio.h>
int foo(void) {
int *p;
int a, b;
int i;
for (i = 0; i < 32; i++) {
p = (&i + i);
printf("i %d : p %p %d\n", i, p, *p);
}
a = *(&i + 11);
b = *(&i + 10);
printf("a %d\n", a);
printf("b %d\n", b);
return a + b;
}
int main(void) {
int a = 8;
int b = 2;
foo();
return 0;
}
And for the record, this kind of stuff is both fun and useful. In particular, it can be invaluable to know when debugging. So I think the question is a good one. That does not mean that this kind of thing should ever end up in any "production" code.
You can solve it by having a global state and a helper function:
static int foo_i, foo_j;
static void foo_setup(int i, int j) {
foo_i = i; foo_j = j;
}
int foo() {
return foo_i % foo_j;
}
int main() {
foo_setup(10,40);
printf("%d\n", foo());
}
To decide whether this is suitable for you, you must consider that this solution is non-reentrant. If you are using threads, you may need to synchronise the calls to foo_setup and foo. Similarly, if you will not call foo immediately after calling foo_setup, you need to carefully craft your code to not use code calling foo_setup, in between.
If you can use c++, you can pass the arguments through the constructor and define an operator() method for the struct.
Thank you for the suggestions. The solution I suggest for the problem I introduced is as follows:
static int helper(int argc, ...) {
unsigned *argv = (unsigned *) (void *)(&argc + 1);
switch (argc) {
case 0: /* do stuff */
case 1: /* do stuff with argv[0] */
case 2: /* do stuff with argv[0], argv[1] */
...
case n: /* do stuff with argv[0], argv[1], ..., argv[n] */
}
}
int goo(void) {
return helper(0);
}
int bar(int arg1) {
return helper(1, arg1);
}
int foo(int arg1, int arg2) {
return helper(2, arg1, arg2);
}
int main(void) {
int arg1 = 3;
int arg2 = 4;
return foo(arg1, arg2);
}