27

Basically I am trying to simulate assembly code in C.

Here is the C code:

int main()
{
   test();
main_next:
   printf("Hello, World!");
}

void test()
{
     goto main_next;
}

Trying to compile this code (Linux 32 bit, gcc 4.6.3), I got this error:

 error: label ‘main_randomtag_next’ used but not defined

Does anyone know how to do this kind of inter-procedural goto in C?

Thank you!

MD XF
  • 7,860
  • 7
  • 40
  • 71
lllllllllllll
  • 8,519
  • 9
  • 45
  • 80

4 Answers4

35

But what about the children? stack?

goto between functions doesn't make any sense if you think about the stack. What will be on the stack when you jump? The source and destination functions could potentially have different arguments and a different return value. Who will the new function return to? Will its return value even make sense to the caller? The caller called the source function, not the destination function.

Return to caller?

Consider your example closely:

int main()
{
   test();
main_next:
   printf("hello, world");
}

void test()
{
     goto main_next;
}

What happens when the goto executes? I presume you'd want this to jump up the stack back to the calling main() function. The goto would effectively be the same as a return, changing the call stack from:

main()                            main()
|                   to            
+--> test()                       

But what if you wanted to jump to a function that isn't in the call stack? What then?

Or replace the current function?

A different interpretation is that the goto would replace the existing test() call with one to main(). The call stack would change from:

main()                            main()
|                   to            |
+--> test()                       +--> main()

Now main() is recursively calling itself, and the lower main() will return to the upper main()—who, by the way, is expecting a void return value but is going to receive an int.

setjmp and longjmp

The closest you can get is with setjmp / longjmp. These allow you to save and restore the stack context for nonlocal goto, allowing you to jump between function calls.

setjmp and longjmp get around the problems I described by (a) saving and restoring the full stack context when jumping, and (b) not allowing jumps if the stack context is no longer valid. I quote from the man page (emphasis mine):

setjmp() and longjmp(3) are useful for dealing with errors and interrupts encountered in a low-level subroutine of a program. setjmp() saves the stack context/environment in env for later use by longjmp(3). The stack context will be invalidated if the function which called setjmp() returns.

To put it another way, longjmp is basically the C equivalent of throwing an exception. A low-level function can unwind the call stack and resume execution at a much higher level function.

It's also awfully tricky to use, and rarely a good idea. Again, from the man page:

setjmp() and sigsetjmp() make programs hard to understand and maintain. If possible an alternative should be used.

Gorisanson
  • 2,202
  • 1
  • 9
  • 25
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
9

GCC generates assembly file first and only then assembles it, so what about creating labels using inline assembly?

void test()
{
    __asm__ volatile ( 
         "jmp main_next"
    );
}


int main()
{
    test();
    __asm__ volatile ( 
        "main_next:"
    );
    printf("hello, world");
}

However, this (obviously) should not be used in real cases, as it doesn't take care of stack at all.

Max Malysh
  • 29,384
  • 19
  • 111
  • 115
  • 4
    This is just one of many ways to create a non-working program by using inline asm to do something the compiler is expecting it *not* to do. You can use [`asm goto`](https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#GotoLabels) to tell the compiler where your asm can jump, but only within the current function for the same reason John's answer explains. – Peter Cordes Dec 30 '16 at 01:58
  • @PeterCordes actually the reason why I checked this question is because I DON'T want to push the current instruction pointer to the stack when performing the call. I share the same goal as the original post, interpreting a byte-code. But I intend to do it using threaded-code, where every instruction jumps onto the next one, with no stack magic involved. – Raslanove Dec 26 '20 at 15:27
  • 1
    @Raslanove: If you want that to work, all the code has to be in the same function anyway for it to possibly be safe, and then you can just use normal `goto` or `switch`. You can *never* safely have execution fall out the end of an asm statement when execution didn't enter at the start of that asm statement. (Except maybe in a debug build where every C statement is compiled to a separate block so you can jump between lines with a debugger, but debug builds are incompatible with performance.) – Peter Cordes Dec 26 '20 at 19:50
  • 1
    @Raslanove: See also [X86 prefetching optimizations: "computed goto" threaded code](https://stackoverflow.com/q/46321531) re: jump threading vs. having a single indirect branch dispatching everything. The latter is actually usually fine with modern branch-prediction strategies (IT-TAGE) in Haswell and later, but see also http://www.emulators.com/docs/nx25_nostradamus.htm for a good old article on jump threading. – Peter Cordes Dec 26 '20 at 19:58
  • 1
    @PeterCordes I reached the same conclusion, having everything inside the same function is compiler friendly. And I can even avoid using assembly at all and get the benefit of being cross-platform. Instead, I ended up using "void* ptr = &&labell;" and "goto *ptr;". We can build up our look up tables, and we can even use pointer arithmetic. And great references by the way. Thanks :) – Raslanove Jan 03 '21 at 16:25
2

well, can't tell better than the wisdom of http://c-faq.com/style/stylewars.html !

Basically, if you want to emulate the behavior of ASM using only C, then you should actually use all the branching abilities of C/C++. And using functions and the function stack is actually an improvement over gotos and tags. That's what structured programming is all about as @ssg wisely said!

zmo
  • 24,463
  • 4
  • 54
  • 90
  • It's not an improvement in all cases, and thus to say that it's an improvement depends. Gotos and labels are more flexible and maintain the same stack context. – Andrew Jun 15 '21 at 10:30
1

It isn't allowed to jump from a function inside another one. The problem is that the function "test" has a return address on the stack and maybe a frame for variables. So in order to do it, you should clean the optional frame and change the address on the stack with the address of main_next:

So in this elementary example, you should just write instead of goto main_next return .

But in other cases it is a little bit more complicated because you must understand what you want.

Do you need to have the code after main_next: as if it was written in test() ? You should remind that the local variable frames of those two functions are different. That means that if you just do a jump then you will use the names of variables used in main but you will refer to the stack frame created by test(). That means that if the two frames aren't compatible, then very strange things may happen.

The problem is what you want exactly and why ?

If you think about just assembly, and you don't use variables in stack frames it is OK. But what are you going to do without variables ?

There are ways to do what you want but you should decide what exactly you need and I may say you how it may be done !

George Kourtis
  • 2,381
  • 3
  • 18
  • 28