Wie springe ich die Programmausführung an eine bestimmte Adresse in C?

Lesezeit: 4 Minuten

Sams Benutzeravatar
Sam

Ich möchte, dass das Programm zu einer bestimmten Adresse im Speicher springt und die Ausführung von dieser Adresse aus fortsetzt. Ich dachte darüber nach, es zu verwenden goto aber ich habe kein Etikett, sondern nur eine Adresse im Speicher.

Sie müssen sich keine Sorgen um die Rückkehr von der Sprungadresse machen.

Bearbeiten: Verwenden des GCC-Compilers

  • Vielleicht hilft Ihnen das stackoverflow.com/questions/61341/…

    – 0x90

    16. November 2011 um 20:16 Uhr


  • Dies ist stark plattformabhängig. Welches Betriebssystem/Compiler verwenden Sie?

    – Rotoglu

    16. November 2011 um 20:16 Uhr

  • Schreiben Sie eine Art Exploit?

    – Kerrek SB

    16. November 2011 um 20:17 Uhr

  • C oder C++? Und warum willst du das tun?

    – David Heffernan

    16. November 2011 um 20:32 Uhr

  • Verstehen Sie, dass, wenn Sie dies tun (entweder mit einer Inline-Assembly-Sprunganweisung oder einem Funktionszeiger-Bodge), alle Variablen ihre Werte über den Sprung hinweg nicht unbedingt behalten? Eine Variable kann an dem Punkt, von dem aus Sie springen, in einem Register und an dem Punkt, zu dem Sie springen, in einem anderen Register zwischengespeichert werden. Dies setzt voraus, dass sich die beiden Punkte sogar in derselben Funktion befinden. Wenn es sich bei der Zieladresse also um in C geschriebenen Code handelt, funktioniert dies fast garantiert nicht.

    – Steve Jessop

    17. November 2011 um 0:58


Randall Cooks Benutzeravatar
Randall Cook

Inline-Assembly ist möglicherweise die einfachste und „eleganteste“ Lösung, obwohl dies höchst ungewöhnlich ist, es sei denn, Sie schreiben einen Debugger oder ein spezielles introspektives System.

Eine andere Möglichkeit könnte darin bestehen, einen Zeiger auf eine void-Funktion zu deklarieren (void (*foo)(void)), dann setzen Sie den Zeiger so, dass er Ihre Adresse enthält, und rufen Sie ihn dann auf:

void (*foo)(void) = (void (*)())0x12345678;
foo();

Es werden Dinge auf den Stapel verschoben, da der Compiler davon ausgeht, dass Sie einen Unterroutinenaufruf ausführen. Da Ihnen die Rückgabe jedoch egal ist, funktioniert dies möglicherweise.

  • Ich habe es mit meinem Setup getestet, mit gcc und mit Nucleus, habe einen minimalen Bootloader geschrieben und es funktioniert …..

    – fazkan

    5. Januar 2016 um 13:23

  • Einige Compiler werten möglicherweise die Speicheradresse (in diesem Fall 0x12345678) als aus intund beschweren Sie sich, wenn Sie versuchen, den Wert des Funktionszeigers darauf zu setzen. Sie sollten die Speicheradresse explizit umwandeln: void (*foo)(void) = (void (*)())0x12345678;.

    – Tyrel Kostyk

    13. Februar 2020 um 20:10 Uhr


gcc hat eine Erweiterung, die das Springen zu einer beliebigen Adresse ermöglicht:

void *ptr = (void *)0x1234567;  // a random memory address
goto *ptr;                      // jump there -- probably crash

Das ist so ziemlich das Gleiche wie die Verwendung eines Funktionszeigers, den Sie auf einen festen Wert setzen, aber es wird tatsächlich eine Sprunganweisung anstelle einer Aufrufanweisung verwendet (sodass der Stapel nicht geändert wird).

  • Beachten Sie, dass dies wirklich GCC-spezifisch ist. Clang erlaubt dies nicht.

    – Martinhans

    29. November 2013 um 9:13 Uhr

  • clang 12 (und möglicherweise früher) unterstützt dies.

    – Allison

    24. August 2020 um 5:04

  • Ein aktuelles Update von Atmel Studio hat diese Linie durchbrochen, die seit einem Jahrzehnt funktioniert … asm("jmp " STR(FLASH_ACTIVE_IMAGE_START_ADDRESS) ); …aber durch die obige Syntax ersetzt funktioniert. Danke!

    – bigjosh

    9. Mai 2021 um 7:56 Uhr

#include <stdio.h>
#include <stdlib.h>

void go(unsigned int addr) {
  (&addr)[-1] = addr;
}

int sub() {
  static int i;
  if(i++ < 10) printf("Hello %d\n", i);
  else exit(0);
  go((unsigned int)sub);
}

int main() {
  sub();
}

Dies ruft natürlich undefiniertes Verhalten hervor, ist plattformabhängig und setzt voraus, dass Codeadressen die gleiche Größe haben wie intusw. usw.

  • Das ist genial. Ich wollte C als Sprach-Backend verwenden und wollte wissen, wie man zu beliebigen Adressen springt. Dann habe ich das gefunden.

    – kirbyfan64sos

    23. November 2014 um 20:48

  • Ich kann dafür garantieren, dass dieser Trick meistens funktioniert, solange die Zielfunktion keine Argumente hat und Sie nicht versuchen, einen Wert zurückzugeben. Ich habe es geändert void* anstatt unsigned int und das hat bei mir funktioniert. Aber als allgemeine Lösung zum Ersetzen von x86 JMP Inline ASM funktioniert es nicht gut genug.

    – Chris Dolan

    2. Juni 2015 um 14:09

Andros Benutzeravatar
Andro

Es sollte ungefähr so ​​aussehen:

unsigned long address=0x80; 

void (*func_ptr)(void) = (void (*)(void))address;
func_ptr();

Allerdings handelt es sich hierbei nicht um einen sehr sicheren Vorgang. Das Springen zu einer unbekannten Adresse führt wahrscheinlich zu einem Absturz!

Benutzeravatar von U007D
U007D

Da die Frage ein C++-Tag hat, finden Sie hier ein Beispiel für a C++ Aufruf einer Funktion mit einer Signatur wie main()–int main(int argc, char* argv[]):

int main(int argc, char* argv[])
{
    auto funcAddr = 0x12345678; //or use &main...
    auto result = reinterpret_cast<int (*)(int, char**)>(funcAddr)(argc, argv);
}

Benutzeravatar der Community
Gemeinschaft

Haben Sie die Kontrolle über den Code an der Adresse, zu der Sie springen möchten? Ist das C oder C++?

Ich schlage es zögernd vor setjmp() / longjmp() wenn Sie C verwenden und ausführen können setjmp() wohin Sie zurückspringen müssen. Allerdings muss man damit SEHR vorsichtig sein.

Informationen zu C++ finden Sie in der folgenden Diskussion longjmp() Shortcut-Ausnahmebehandlung und Destruktoren-Destruktoren. Dies würde mich noch zögernder machen, die Verwendung in C++ vorzuschlagen.

C++: Sichere Verwendung von longjmp und setjmp?

Benutzeravatar von İlkerK
İlkerK

Dies ist, was ich für meinen Bootstrap-Loader verwende (MSP430AFE253,Compiler = gcc,CodeCompeserStudio);

#define API_RESET_VECT 0xFBFE
#define JUMP_TO_APP()  {((void (*)()) (*(uint16_t*)API_RESET_VECT)) ();}

1453610cookie-checkWie springe ich die Programmausführung an eine bestimmte Adresse in C?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy