You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

非内联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

解决方案

核心问题拆解

  1. C代码中的标签(如tree:、dirt:)是编译器内部符号,不会被导出到全局符号表,汇编无法直接跳转这些标签
  2. main.c中用户名输入的while(1)循环无退出条件,合法输入后仍会陷入循环
  3. 汇编navigation函数错误引用全局变量go,未使用传入的选择参数
  4. 汇编中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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 21:17:05