非内联Assembly跳转至C程序标签的实现问题
问题描述
我没有使用内联汇编,当前assembly.s中的je tree等指令无法跳转至C程序内的标签,甚至无法退出输入用户名的循环。我知晓这类标签可能仅在汇编内部可用,特此请教是否存在更合适的方法,能从汇编的比较逻辑跳转至C程序的特定代码块。相关代码文件如下:
main.c
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> #include <unistd.h> #include "header.h" //Plot : User must get the stick, line and bait in order to catch a huge fish to win a fishing contest and return home. #define stick (1 << 0) #define line (1 << 1) #define bait (1 << 2) int go = 0; int main () { int fishing_pole = 0; //A fully assembled fishing pole is int == 7 char name[20]; int len; int tries = 1; int fish_size = 20; time_t start, end; int elapsed; //Intro printf("You wake up on a sandbar in a place you don't recognize"); elipses(); sleep(2); printf("\nSomeone calls out to you in the distance, and as you turn to look you see someone approaching you.\n"); //Get the name yellow(); printf("You must be the last entry for the fishing contest!\nWhat's your name?\n"); //MY NAME IS... //Keeps user looped until they enter a name under 20 characters. while (1) { blue(); printf("My name is... "); scanf(" %s", name); reset(); len = strlen(name); if ( len < 20 ) { yellow(); printf("Alright, %s, All you'll need is a fishing pole!\n", name); elipses(); printf("You don't have a fishing pole?\n"); sleep(1); printf("Well that's alright, certainly you could make one with some materials nearby!\nLet me know when you've got a pole and we can begin!\n"); reset(); nav_prompt(go); } else { printf("I don't really know if I can remember that long of a name, maybe give me a shorter nickname I can call you?\n"); } } tree: if ( !(fishing_pole & 0001) ) { printf("You approach the tree you saw and pull a branch from it. This looks like a good fishing pole!\n"); fishing_pole |= stick; nav_prompt(go); } else { printf("You've already got the stick!\n "); nav_prompt(go); } dirt: if ( !(fishing_pole & 0010) ) { printf("You approach the pile of dirt, dig for a moment and pull a worm from the ground.\nThis should be good for bait!\n"); nav_prompt(go); } else { printf("You've already got your hands dirty and dug up the bait!\n"); nav_prompt(go); } spider: if ( !(fishing_pole & 0100) ) { printf("You approach the spider web, pull it down and spin it into a strong line!\nThis ought to work for a fishing line."); nav_prompt(go); } else { printf("You've already got the spider web for line, now get outta here before the spider finds out!\n"); nav_prompt(go); } crowd: if ( !(fishing_pole & 0111) ) { yellow(); printf("You think you're ready, %s? Let's see if you've got a fishing pole!\n", name); if ( fishing_pole == 7 ) { printf("Hey that looks great, let's get to fishing!"); fishing(); } else { printf("Hey it looks like you're missing something, %s. Finish your pole and we'll wait!\n", name); } } bad: printf("Not sure where you think you're going, %s, but it's in the wrong direction!\n", name); nav_prompt(go); fish: reset(); //Actual gameplay!! printf("You line up next to the other fishing competitors and cast your line.\n"); while (1) { //regenerate how long it takes for a fish to hook every loop int random = (rand() % 3) + 1; while ( random < 0 ) { elipses(); --random; } //calculate how long it takes for the player to reel printf("Fish on! Press any key to reel it in!\n"); start = time(NULL); getchar(); end = time(NULL); elapsed = difftime(end, start); //Fish get easier to catch on every attempt if ( elapsed > tries ) { printf("The fish got away!\n"); printf("You cast your line again.\n"); ++tries; --fishing_pole; } else { printf("You reel in the fish!"); return 0; } } if ( (fishing_pole - tries) < 1 ) { fishing_pole = 1; yellow(); printf("The fish you caught was %d inches long. Unfortunately that's not big enough and you were beaten...\nGo ahead and try to make a better fishing pole, and try and catch the first couple fish next time!\n", fishing_pole); fishing_pole = 0; nav_prompt(go); } else { yellow(); printf("The fish you caught was %d inches long!\n", fishing_pole); printf("Really great work, it looks like you can leave this place finally, %s!\n", name); printf("Have a safe trip and come back to visit us sometime!\n"); reset(); elipses(); printf("Your vision begins to go blurry and you feel dizzy"); elipses(); } return 0; }
assembly.s
.intel_syntax noprefix extern go global tree global dirt global spider global crowd global navigation global fishing navigation: mov rax, 1 cmp rax, go je tree mov rax, 2 cmp rax, go je dirt mov rax, 3 cmp rax, go je spider mov rax, 4 cmp rax, go je crowd jmp bad xor rdx, rdx ret fishing: jmp fish ret
functions.c
#include <stdio.h> #include <unistd.h> void red () { printf("\033[0;31m"); } void green () { printf("\033[0;32m"); } void yellow () { printf("\033[0;33m"); } void blue () { printf("\033[0;34m"); } void reset () { printf("\033[0m"); } void elipses () { printf("."); sleep(1); printf("."); sleep(1); printf(".\n"); sleep(1); } int navigation(int x){}; int nav_prompt (int x) { reset(); printf("You look around and see a tree, a pile of dirt, a spider's web and a few people standing around down the beach.\nWhere would you like to go? [1/2/3/4, Tree/Dirt/Spider Web/Group of people]\n"); //[1/2/3/4, Tree/Dirt/Spider Web/Group of people] scanf(" %d", &x); navigation(x); }
header.h
#ifndef HEADER_H_ #define HEADER_H_ void red (); void blue (); void green (); void yellow (); void reset (); void elipses (); int navigation(int x); int nav_prompt (); void fishing(); #endif
解决方案
核心问题拆解
- C代码中的标签(如
tree:、dirt:)是编译器内部符号,不会被导出到全局符号表,汇编无法直接跳转这些标签 main.c中用户名输入的while(1)循环无退出条件,合法输入后仍会陷入循环- 汇编
navigation函数错误引用全局变量go,未使用传入的选择参数 - 汇编中
jmp bad、jmp fish同样无法定位C内的标签
具体修复步骤
1. 将C中标签逻辑封装为可调用函数
把原标签对应的代码改成独立函数,让汇编能通过函数调用实现逻辑跳转:
// main.c中新增函数 void handle_tree(int *fishing_pole) { if ( !(*fishing_pole & stick) ) { printf("You approach the tree you saw and pull a branch from it. This looks like a good fishing pole!\n"); *fishing_pole |= stick; nav_prompt(); } else { printf("You've already got the stick!\n "); nav_prompt(); } } void handle_dirt(int *fishing_pole) { if ( !(*fishing_pole & bait) ) { printf("You approach the pile of dirt, dig for a moment and pull a worm from the ground.\nThis should be good for bait!\n"); *fishing_pole |= bait; nav_prompt(); } else { printf("You've already got your hands dirty and dug up the bait!\n"); nav_prompt(); } } void handle_spider(int *fishing_pole) { if ( !(*fishing_pole & line) ) { printf("You approach the spider web, pull it down and spin it into a strong line!\nThis ought to work for a fishing line."); *fishing_pole |= line; nav_prompt(); } else { printf("You've already got the spider web for line, now get outta here before the spider finds out!\n"); nav_prompt(); } } void handle_crowd(int *fishing_pole, char *name) { yellow(); printf("You think you're ready, %s? Let's see if you've got a fishing pole!\n", name); if ( *fishing_pole == 7 ) { printf("Hey that looks great, let's get to fishing!"); fishing(fishing_pole, name); } else { printf("Hey it looks like you're missing something, %s. Finish your pole and we'll wait!\n", name); nav_prompt(); } } void handle_bad(char *name) { printf("Not sure where you think you're going, %s, but it's in the wrong direction!\n", name); nav_prompt(); } void fishing(int *fishing_pole, char *name) { reset(); printf("You line up next to the other fishing competitors and cast your line.\n"); int tries = 1; while (1) { int random = (rand() % 3) + 1; while ( random > 0 ) { elipses(); --random; } printf("Fish on! Press any key to reel it in!\n"); time_t start = time(NULL); getchar(); time_t end = time(NULL); int elapsed = difftime(end, start); if ( elapsed > tries ) { printf("The fish got away!\n"); printf("You cast your line again.\n"); ++tries; --(*fishing_pole); } else { printf("You reel in the fish!"); exit(0); } } }
同时更新header.h添加函数声明:
void handle_tree(int *fishing_pole); void handle_dirt(int *fishing_pole); void handle_spider(int *fishing_pole); void handle_crowd(int *fishing_pole, char *name); void handle_bad(char *name); void fishing(int *fishing_pole, char *name);
2. 重构汇编代码,通过函数调用实现逻辑分支
修改assembly.s,根据传入的选择参数调用对应的C函数:
.intel_syntax noprefix extern handle_tree extern handle_dirt extern handle_spider extern handle_crowd extern handle_bad global navigation ; x86-64 System V调用约定:rdi=选择值,rsi=fishing_pole指针,rdx=name指针 navigation: cmp rdi, 1 je call_tree cmp rdi, 2 je call_dirt cmp rdi, 3 je call_spider cmp rdi, 4 je call_crowd jmp call_bad call_tree: call handle_tree ret call_dirt: call handle_dirt ret call_spider: call handle_spider ret call_crowd: call handle_crowd ret call_bad: call handle_bad ret
3. 修复main.c的循环和函数调用逻辑
- 给用户名输入循环添加退出条件,进入主游戏逻辑:
// 修改main中用户名输入的分支 if ( len < 20 ) { yellow(); printf("Alright, %s, All you'll need is a fishing pole!\n", name); elipses(); printf("You don't have a fishing pole?\n"); sleep(1); printf("Well that's alright, certainly you could make one with some materials nearby!\nLet me know when you've got a pole and we can begin!\n"); reset(); break; // 退出输入循环 }
- 修改
nav_prompt返回用户选择,更新主逻辑循环:
// 修改functions.c中的nav_prompt int nav_prompt () { reset(); int choice; printf("You look around and see a tree, a pile of dirt, a spider's web and a few people standing around down the beach.\nWhere would you like to go? [1/2/3/4, Tree/Dirt/Spider Web/Group of people]\n"); scanf(" %d", &choice); return choice; } // 在main.c的用户名循环后添加主逻辑 while(1) { int choice = nav_prompt(); navigation(choice, &fishing_pole, name); }
编译注意事项
编译时需将所有文件链接,执行命令:
gcc main.c functions.c assembly.s -o fishing_game
内容的提问来源于stack exchange,提问作者komsire22
相关产品推荐
相关产品推荐

