12
votes

Comment sauter l'exécution du programme à une adresse spécifique en C?

Je souhaite que le programme passe à une adresse spécifique en mémoire et de continuer à exécuter à partir de cette adresse. J'ai pensé à utiliser goto mais je n'ai pas une étiquette plutôt qu'une adresse en mémoire.

Il n'est pas nécessaire de vous inquiéter de retour de l'adresse de saut.

Edit: Utilisation du compilateur GCC

c c++

6 commentaires

peut-être que cela pourrait vous aider Stackoverflow.com/Questions/61341/...


C'est une plate-forme sauvagement dépendante; quel système d'exploitation / compilateur utilisez-vous?


Vous écrivez une sorte d'exploit?


C ou c ++? Et pourquoi voulez-vous faire cela?


Comprenez-vous que si vous faites cela (soit avec une instruction de saut d'assemblage en ligne, ou un corps de pointeur de fonction), les variables ne conserveront pas nécessairement leurs valeurs à travers le saut? Une variable peut être mise en cache dans un seul registre au point que vous sautez et un registre différent dans le point que vous sautez, et cela suppose que les deux points sont même dans la même fonction. Donc, si l'adresse de destination est écrite en C, il est presque garanti de ne pas fonctionner.


N'oubliez pas d'accepter les réponses que vous aimez.


8 Réponses :


29
votes

L'assemblage en ligne pourrait être la solution la plus facile et la plus élégante ", bien que cela soit très inhabituel, à moins que vous n'écrivez à un débogueur ou à un système introspectif spécialisé.

Une autre option peut être de déclarer un pointeur à une fonction vide ( void (* foo) (void) ), puis définissez le pointeur pour contenir votre adresse, puis l'appelez: xxx

il y aura Les choses ont poussé sur la pile car le compilateur pense que vous faites un appel de sous-programme, mais que vous vous souciez de revenir, cela pourrait fonctionner.


2 commentaires

Je l'ai testé avec ma configuration, à l'aide de GCC et avec NUCLEUS, écrivez un chargeur de démarrage minimal et ça marche .....


Certains compilateurs peuvent évaluer l'adresse mémoire (0x12345678 dans ce cas) sous forme d'un int et de vous plaindre lorsque vous essayez de définir la valeur du pointeur de fonction. Vous devez expliquer explicitement l'adresse de la mémoire: void (* foo) (void) = (vide (*) ()) 0x12345678; .



5
votes

Il devrait ressembler à quelque chose comme ceci:

unsigned long address=0x80; 

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


1 commentaires

Vous devez également prendre en compte le problème des adresses virtuelles lors de la gestion de programmes sur un système d'exploitation.



10
votes
#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();
}
Of course, this invokes undefined behavior, is platform-dependent, assumes that code addresses are the same size as int, etc, etc.

2 commentaires

C'est génie. Je cherchais à utiliser C en tant que backend de langue et je devais savoir comment sauter aux adresses arbitraires. Ensuite, j'ai trouvé cela.


Je peux garantir que cette affaire fonctionne principalement, tant que la fonction de destination n'a aucun argument et que vous n'essayez pas de retourner une valeur. Je l'ai changé pour être void * au lieu de non signé INT et qui a fonctionné pour moi. Mais en tant que solution générale pour remplacer X86 JMP en ligne ASM, ne fonctionne pas assez bien.



0
votes

Avez-vous le contrôle du code à l'adresse que vous avez l'intention de sauter? Est-ce c ou c ++?

Je suggère avec hésitation setjmp () / longjmp () si vous utilisez c et pouvez exécuter setJMP () où vous devez retourner. Cela étant dit, vous devez faire très attention à ceux-ci.

Quant à C ++, voir la discussion suivante sur LONGJMP () Raccourcissement destructeurs d'exception et destructeurs destructeurs. Cela me rendrait encore plus hésitant à suggérer qu'il est utilisé en C ++.

C ++: sûr d'utiliser LONGJMP et SETJMP?


2 commentaires

Je pense que SETJMP () et LongJMP () sont des mentaux pour une pile non standard de déroulement alias. Simulation de la manipulation d'exception dans C.


La manipulation des exceptions est une utilisation majeure pour eux, oui. Cela étant dit, selon ce que le code en question ressemble, il serait possible d'utiliser une longjmp () pour passer à un point connu du code sans se soucier de l'adresse à condition qu'un appel SETJMP () puisse être exécuté à ce sujet. indiquer.



20
votes

GCC a une extension qui permet de sauter à une adresse arbitraire: xxx

ceci est à peu près identique à l'utilisation d'un pointeur de fonction que vous définissez sur une valeur fixe, mais elle utilisera réellement une instruction de saut plutôt qu'une instruction d'appel (la pile ne sera donc modifiée)


3 commentaires

Notez que cela est vraiment spécifique GCC. Clang ne permet pas cela.


Clang 12 (et éventuellement plus tôt) soutient cela.


Une mise à jour récente d'Atmel Studio a cassé cette ligne qui travaillait depuis une décennie ... ASM ("JMP" STR (flash_active_image_start_address)); ... mais remplacé par la syntaxe ci-dessus fonctionne. Merci!



0
votes

Je propose ce code:

asm(
"LDR R0,=0x0a0000\n\t" /* Or 0x0a0000 for the base Addr. */
"LDR R0, [R0, #4]\n\t" /* Vector+4 for PC */
"BX R0"
);


0 commentaires

2
votes

Étant donné que la question a une balise C ++, voici un exemple d'appel C ++ à une fonction avec une signature comme principal () - int Main (int Argc, char * argv [ ]) : xxx


0 commentaires

1
votes

C'est ce que j'utilise pour mon chargeur de bootstrap (MSP430afe253, Compiler = GCC, CODECOMPESTUDIO);

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


0 commentaires