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

C转汇编求助:ChangeVector函数改写后输出结果异常

问题描述

需要将changeVector函数改写为不使用变量、且必须包含push ebp/mov ebp, esp栈帧指令的汇编代码。原C代码运行正常,但自行编写的汇编版本无论输入是什么,输出始终固定为0xFFFFFFFE 0X0000000C,结果完全错误。

例如测试用例:

  • n=2,向量元素为-2、12
  • i=1,k=5,v=1
    正确输出应为0XFFFFFFFF 0X0842108c,但汇编实现无法得到该结果。

原C代码

void changeBit(unsigned int *vector, int indice, int valor) {
    int posicion = indice / 32; // 找到位所在的向量元素位置
    int bit = 31 - (indice % 32); // 找到元素内的具体位偏移

    __asm {
        mov esi, vector
        mov edi, posicion
        mov ecx, bit
        mov eax, dword ptr [esi + edi * 4] ; 加载当前向量元素的值

        cmp valor, 0
        jne set_bit ; 若值不为0则跳转到置位逻辑

        btr [esi + edi * 4], ecx ; 将指定位清零
        jmp done

    set_bit:
        mov edx, 1
        shl edx, cl ; 将1移到目标位的位置
        or dword ptr [esi + edi * 4], edx ; 用OR操作置位
    done:
    }
}

void changeVector(unsigned int *vector, int n, int i, int k, int v) { 
    // 循环处理从i开始、步长为k的所有位,直到超出向量总位数
    for (int j = 0; (i + j * k) < n * 32; j++) { 
        changeBit(vector, (i + j * k), v); // 调用位修改函数
    }
}

int main() {
    int n;
    do {
        printf("Enter the size of the vector (n): ");
        scanf("%d", &n);
        if (n <= 0) 
        {
            printf("The size of the vector must be greater than 0. Please try again.\n");
        }
    } while (n <= 0); 

    unsigned int *vector = (unsigned int *)calloc(n, sizeof(unsigned int)); 

    if (vector == NULL) {
        printf("Error allocating memory for the vector.\n");
        return 1;
    }

    printf("Enter values for each element of the vector:\n"); 
    for (int i = 0; i < n; i++) {
        printf("Enter the value of the element: ");
        scanf("%u", &vector[i]);
    }

    int i, k, v; 
    printf("Enter the initial index (i): ");
    scanf("%d", &i);
    printf("Enter the step (k): ");
    scanf("%d", &k);
    printf("Enter the value (v, 0 or 1): ");
    scanf("%d", &v);

    printf("The original unsigned int vector (size %d) would be:\n", n);
    for (int i = 0; i < n; i++) {
        printf("0x%08X \n", vector[i]);
    }
    changeVector(vector, n, i, k, v);
    printf("\nAfter the assignment, the vector is:\n");
    for (int i = 0; i < n; i++) {
        printf("0x%08X \n", vector[i]);
    }

    free(vector);
    return 0;
}

自行编写的错误汇编代码

void changeVector(unsigned int *vector, int n, int i, int k, int v) {
    __asm {
        mov esi, vector    ; 向量地址
        mov ecx, n         ; 向量元素个数
        mov edx, i         ; 初始索引
        mov ebx, k         ; 步长

    loop_start:
        cmp edx, ecx      ; 比较索引与向量大小
        jge loop_end       ; 若索引 >= 大小则退出循环

        ; 根据当前索引(edx)计算位索引
        mov eax, edx       ; 将索引复制到eax
        imul eax, 32       ; 索引乘以32
        mov edi, eax       ; 保存结果到edi

        ; 调用changeBit函数,传入计算后的位索引(edi)和值(v)
        push v
        push edi
        push esi
        call changeBit
        add esp, 12        ; 函数调用后清理栈

        ; 根据步长(ebx)更新索引(edx)
        add edx, ebx

        jmp loop_start     ; 跳回循环开始

    loop_end:
    }
}
问题分析与修复

你的汇编代码存在三个核心错误,导致结果完全偏离预期:

1. 循环条件完全错误

原C代码的循环条件是当前处理的位索引 < 向量总位数(即(i + j*k) < n*32),但你的汇编里直接比较edx(当前位索引)和ecx(向量元素个数n),相当于用位索引和元素个数比,完全不符合逻辑。

2. 错误放大了位索引

原C中changeBit的第二个参数就是原始位索引(比如测试用例中的1、6、11...),但你额外做了imul eax,32,把位索引乘以32,导致传入changeBit的索引是正确值的32倍,直接修改了完全无关的内存位置。

3. 未遵循栈帧要求与寄存器调用约定

你没有添加push ebp/mov ebp, esp的栈帧指令,同时ebx是非易失性寄存器(调用者需要保存),直接修改会破坏上层函数的上下文。

修复后的汇编代码

void changeVector(unsigned int *vector, int n, int i, int k, int v) {
    __asm {
        ; 建立栈帧
        push ebp
        mov ebp, esp

        ; 保存非易失性寄存器(ebx)
        push ebx

        ; 从栈帧中获取函数参数
        mov esi, [ebp+8]    ; vector 参数
        mov ecx, [ebp+12]   ; n 参数
        mov edx, [ebp+16]   ; i 参数(初始位索引)
        mov ebx, [ebp+20]   ; k 参数(步长)
        mov eax, [ebp+24]   ; v 参数

        ; 计算向量总位数:n * 32,保存到edi
        mov edi, ecx
        imul edi, 32

    loop_start:
        ; 循环条件:当前位索引(edx) < 总位数(edi)
        cmp edx, edi
        jge loop_end

        ; 调用changeBit:参数顺序是vector, 位索引(edx), v(eax)
        push eax
        push edx
        push esi
        call changeBit
        add esp, 12         ; 清理栈上的3个参数

        ; 更新位索引:edx += k(ebx)
        add edx, ebx

        jmp loop_start

    loop_end:
        ; 恢复非易失性寄存器
        pop ebx
        ; 销毁栈帧
        pop ebp
    }
}

修复说明

  • 严格按照要求添加了栈帧的建立与销毁指令
  • 修正循环条件:用当前位索引和总位数n*32比较
  • 移除了错误的位索引乘32操作,直接将当前位索引传入changeBit
  • 保存并恢复了非易失性寄存器ebx,符合x86调用约定
  • 从栈帧中获取参数,贴合“不使用变量”的要求

内容的提问来源于stack exchange,提问作者Leah M

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 12:07:06