Why the setjmp and longjmp I wrote can not work?

Z

Zheng Da

I wrote a simple one as follow:

typedef struct __myjmp_buf
{
int efp;
int epc;
}myjmp_buf;

int mysetjmp(myjmp_buf env)
{
int reval=0;
__asm__("movl %%ebp,%0":"=r"(env[0].efp));
__asm__("movl $1f,%0\n\t"
"1:"
:"=r"(env[0].epc));
return reval;
}

void mylongjmp(myjmp_buf env , int val)
{
__asm__("movl %1,-4(%0)\n\t"
"movl %0,%%ebp\n\t"
"jmp %2"
::"r"(env[0].efp),
"r"(val),
"r"(env[0].epc));
}

myjmp_buf buf;

int test()
{
int i=0;
i++;
mylongjmp(buf , 1);
return 0;
}

int main()
{
if(mysetjmp(buf))
{
printf("return success\n");
}
printf("pc:%x,fp:%x\n" , buf[0].epc , buf[0].efp);
printf("main address:%x\n" , main);
test();
exit(0);
}

When the computer execute jmp %2, and gives me a segment fault.
Why the address I save is a invalid address?
By the way, I want to find the codes of setjmp and longjmp in glibc,
but can not get it, and waht I find does not seem to be what I want.
How to find the codes of setjmp and longjmp which can run under Linux
and x86?
Thank you
 
M

Michael Mair

Zheng said:
I wrote a simple one as follow:
<snip>
Sorry, your code does not compile; you forgot to
When the computer execute jmp %2, and gives me a segment fault.
Why the address I save is a invalid address?
By the way, I want to find the codes of setjmp and longjmp in glibc,
but can not get it, and waht I find does not seem to be what I want.
How to find the codes of setjmp and longjmp which can run under Linux
and x86?

Please provide a minimal compiling example in standard
C or repost your request in a newsgroup where your
platform/operating system/compiler-combination is on-topic.

Information about setjmp/longjmp() can be found below.


Cheers
Michael

PS: The following is only a quote from the standard.

As for setjmp()/longjmp():

7.13 Nonlocal jumps <setjmp.h>

1 The header <setjmp.h> defines the macro setjmp, and declares one
function and one type, for bypassing the normal function call and
return discipline.207)
,---
| 207) These functions are useful for dealing with unusual conditions
| encountered in a low-level function of a program.
`---

2 The type declared is
jmp_buf
which is an array type suitable for holding the information needed to
restore a calling environment. The environment of a call to the setjmp
macro consists of information sufficient for a call to the longjmp
function to return execution to the correct block and invocation of that
block, were it called recursively. It does not include the state of the
floating-point status flags, of open files, or of any other component of
the abstract machine.

3 It is unspecified whether setjmp is a macro or an identifier declared
with external linkage. If a macro definition is suppressed in order to
access an actual function, or a program defines an external identifier
with the name setjmp, the behavior is undefined.

7.13.1 Save calling environment
7.13.1.1 The setjmp macro

Synopsis
1
#include <setjmp.h>
int setjmp(jmp_buf env);

Description
2 The setjmp macro saves its calling environment in its jmp_buf argument
for later use by the longjmp function.

Returns
3 If the return is from a direct invocation, the setjmp macro returns
the value zero. If the return is from a call to the longjmp function,
the setjmp macro returns a nonzero value.

Environmental limits
4 An invocation of the setjmp macro shall appear only in one of the
following contexts:
— the entire controlling expression of a selection or iteration
statement;
— one operand of a relational or equality operator with the other
operand an integer constant expression, with the resulting expression
being the entire controlling expression of a selection or iteration
statement;
— the operand of a unary ! operator with the resulting expression being
the entire controlling expression of a selection or iteration
statement; or
— the entire expression of an expression statement (possibly cast to
void).

5 If the invocation appears in any other context, the behavior is undefined.

7.13.2 Restore calling environment
7.13.2.1 The longjmp function

Synopsis
1
#include <setjmp.h>
void longjmp(jmp_buf env, int val);

Description
2 The longjmp function restores the environment saved by the most recent
invocation of the setjmp macro in the same invocation of the program
with the corresponding jmp_buf argument. If there has been no such
invocation, or if the function containing the invocation of the setjmp
macro has terminated execution208) in the interim, or if the invocation
of the setjmp macro was within the scope of an identifier with variably
modified type and execution has left that scope in the interim, the
behavior is undefined.
,---
| 208) For example, by executing a return statement or because another
| longjmp call has caused a transfer to a setjmp invocation in a
| function earlier in the set of nested calls.
`---

3 All accessible objects have values, and all other components of the
abstract machine209) have state, as of the time the longjmp function was
called, except that the values of objects of automatic storage duration
that are local to the function containing the invocation of the
corresponding setjmp macro that do not have volatile-qualified type
and have been changed between the setjmp invocation and longjmp call are
indeterminate.
,---
| 209) This includes, but is not limited to, the floating-point status
| flags and the state of open files.
`---

Returns
4 After longjmp is completed, program execution continues as if the
corresponding invocation of the setjmp macro had just returned the value
specified by val. The longjmp function cannot cause the setjmp macro to
return the value 0; if val is 0, the setjmp macro returns the value 1.

5 EXAMPLE
The longjmp function that returns control back to the point of the
setjmp invocation might cause memory associated with a variable length
array object to be squandered.

#include <setjmp.h>
jmp_buf buf;
void g(int n);
void h(int n);
int n = 6;

void f(void)
{
int x[n]; // valid: f is not terminated
setjmp(buf);
g(n);
}

void g(int n)
{
int a[n]; // a may remain allocated
h(n);
}

void h(int n)
{
int b[n]; // b may remain allocated
longjmp(buf, 2); // might cause memory loss
}
 
Z

Zheng Da

Thank you for advice and information you provided.
I compile the program in Fedora core1 which runs in x86, and the
version of gcc is 3.3.2.
By the way, the program has been a minimal compiling example, and there
is no error to compile it in my system but a warning "indirect jmp
without '*' "
But I do not know what the warning mean.
 
K

Keith Thompson

Zheng Da said:
Thank you for advice and information you provided.
I compile the program in Fedora core1 which runs in x86, and the
version of gcc is 3.3.2.
By the way, the program has been a minimal compiling example, and there
is no error to compile it in my system but a warning "indirect jmp
without '*' "
But I do not know what the warning mean.

Please don't assume your readers can see the article to which you're
replying. You need to provide some context so each article can be
read on its own. Google makes it unnecessarily difficult to do this
properly, but there is a workaround:

If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers.

We don't know what the warning means either, because it doesn't refer
to anything in standard C. "__asm__" is not part of the C standard;
it's apparently a gcc extension.

You might try gnu.gcc.help.
 
Z

Zheng Da

Keith said:
Please don't assume your readers can see the article to which you're
replying. You need to provide some context so each article can be
read on its own. Google makes it unnecessarily difficult to do this
properly, but there is a workaround:

If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers.

We don't know what the warning means either, because it doesn't refer
to anything in standard C. "__asm__" is not part of the C standard;
it's apparently a gcc extension.

You might try gnu.gcc.help.

First, I am sorry. I did know it made so much trouble when I click
"Reply" link at the bottom of the article in google newsgroup.
I think I should redescribe the problem I met.
I wrote a program as follow:
#include <stdio.h>

typedef struct __myjmp_buf
{
int efp;
int epc;
}myjmp_buf;

int mysetjmp(myjmp_buf env)
{
int reval=0;
__asm__("movl %%ebp,%0":"=r"(env[0].efp));
__asm__("movl $1f,%0\n\t"
"1:"
:"=r"(env[0].epc));
return reval;
}

void mylongjmp(myjmp_buf env , int val)
{
__asm__("movl %1,-4(%0)\n\t"
"movl %0,%%ebp\n\t"
"jmp %2"
::"r"(env[0].efp),
"r"(val),
"r"(env[0].epc));
}

myjmp_buf buf;

int test()
{
int i=0;
i++;
mylongjmp(buf , 1);
return 0;
}

int main()
{
if(mysetjmp(buf))
{
printf("return success\n");
}
printf("pc:%x,fp:%x\n" , buf[0].epc , buf[0].efp);
printf("main address:%x\n" , main);
test();
exit(0);
}
When the computer execute jmp %2, and gives me a segment fault.
I do not know why the address I save is a invalid address, and wonder
to know what should I do if I want that mysetjmp and mylongjmp can work
like setjmp and longjmp.
My platform is x86, the system I use is Fedora core1, and I compile the
program with gcc.
 
F

Flash Gordon

Zheng Da wrote:

First, I am sorry. I did know it made so much trouble when I click
"Reply" link at the bottom of the article in google newsgroup.

Please send a complaint to Google about the problems their interface
causes you and others.

Also, you don't need to quote everything, snip out the bits you are not
replying too.

void mylongjmp(myjmp_buf env , int val)
{
__asm__("movl %1,-4(%0)\n\t"
"movl %0,%%ebp\n\t"
"jmp %2"
::"r"(env[0].efp),
"r"(val),
"r"(env[0].epc));
}

When the computer execute jmp %2, and gives me a segment fault.

<snip>

I'm sure I've seen posts telling you that __asm__ is not on topic here
because it is a system specific extension and we don't deal with those.
Please ask about your problem in a GNU or Linux group, or possibly an
x86 group since this is x86 assembler.
 
Z

Zheng Da

I'm sure I've seen posts telling you that __asm__ is not on topic here
because it is a system specific extension and we don't deal with those.
Please ask about your problem in a GNU or Linux group, or possibly an
x86 group since this is x86 assembler.

OK. Thank you all the same
 
J

jacob navia

Zheng said:
I wrote a simple one as follow:

typedef struct __myjmp_buf
{
int efp;
int epc;
}myjmp_buf;

int mysetjmp(myjmp_buf env)
{
int reval=0;
__asm__("movl %%ebp,%0":"=r"(env[0].efp));
__asm__("movl $1f,%0\n\t"
"1:"
:"=r"(env[0].epc));
return reval;
}

void mylongjmp(myjmp_buf env , int val)
{
__asm__("movl %1,-4(%0)\n\t"
"movl %0,%%ebp\n\t"
"jmp %2"
::"r"(env[0].efp),
"r"(val),
"r"(env[0].epc));
}

myjmp_buf buf;

int test()
{
int i=0;
i++;
mylongjmp(buf , 1);
return 0;
}

int main()
{
if(mysetjmp(buf))
{
printf("return success\n");
}
printf("pc:%x,fp:%x\n" , buf[0].epc , buf[0].efp);
printf("main address:%x\n" , main);
test();
exit(0);
}

When the computer execute jmp %2, and gives me a segment fault.
Why the address I save is a invalid address?
By the way, I want to find the codes of setjmp and longjmp in glibc,
but can not get it, and waht I find does not seem to be what I want.
How to find the codes of setjmp and longjmp which can run under Linux
and x86?
Thank you
1)
Your program will not compile
In the function "mysetjump" you declare "env" as a structure
"myjmp_buf" but you access it as an array.

2) You are passing the structure myjump_buf by value to the
function mysetjmp, so any changes or assignments done to that
structure are destroyed when the function returns. You are working
in a COPY of the structure

3) Do not use the embedded assembler of gcc. It is utterly
incomprehensible. Write setjmp like this:

mov 0x4(%esp,1),%edx ;save address of buffer in edx
mov (%esp,1),%ecx ;save return address in ecx
mov %ebx,0xc(%edx) ; save ebx
mov %esi,0x10(%edx) ; save esi
mov %edi,0x14(%edx) ; save edi
mov %ecx,0x8(%edx) ; save return address
mov %eax,0x1c(%edx) ; save eax
mov %ebp,0x4(%edx) ; save ebp
mov %esp,%eax ; save esp+4
add $0x4,%eax
mov %eax,(%edx) ; at the bottom of the buffer
xor %eax,%eax ; return zero
ret

I leave you the long jump routine as an exercise for the reader :)
 
C

Christian Bau

"Zheng Da said:
void mylongjmp(myjmp_buf env , int val)
{
__asm__("movl %1,-4(%0)\n\t"
"movl %0,%%ebp\n\t"
"jmp %2"
::"r"(env[0].efp),
"r"(val),
"r"(env[0].epc));
}

To be honest, implementing setjmp and longjmp is one of the things that
you shouldn't even try if you have to ask people how to do it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,054
Latest member
LucyCarper

Latest Threads

Top