【问题标题】:Get returned char from a C function using inline assembly使用内联汇编从 C 函数中获取返回的字符
【发布时间】:2016-11-21 22:40:48
【问题描述】:

我有一个使用内联汇编的函数,它基本上调用一个 C 函数,获取返回值,并将该值作为参数传递给另一个返回字符的函数。

void convertText(FILE *arch, FILE *result)
{
    int i = 0;
    int n = arch->size;

    _asm {
    mov esi, 0
whileS:
    cmp esi, n
    jge end

    mov ebx, result
    mov ebx, [ebx]result.information ; Pointer to an array of characters

    push esi ; Push parameters to get5bitsFunc
    push arch ; Push parameters to get5bitsFunc

    call get5bitsFunc
    pop arch ; Restore values
    pop esi ; Restore values

    push eax ; push get5bitsFunc returned value to codify as parameter
    call codify
   mov edi, eax ;  <- HERE move returned value from codify to edi register
    pop eax ; restore eax

    inc esi
    jmp whileS
end:

    }
}

将编码视为类型的函数

unsigned char codify(unsigned char parameter) {
    unsigned char resp;

    // Do something to the parameter
    resp = 'b'; // asign value to resp
    return resp;
}

我已经测试了 codify 并且可以正常使用 C 代码返回我想要的值。问题是,当我在标记为“-> Here”的行中运行和调试内联汇编中的convertText代码时,eax中返回的值是3424242类型的东西,而不是ascii表中的97或以上我需要。

如何获取 char 值?

【问题讨论】:

  • unsigned char 只有 1 个字节,而 eax 是 32 位(4 字节)寄存器。如果codify() 只返回一个字节,那么返回值将存储在aleax 的第一个字节)中,而eax 的其余部分保持不变(这将导致垃圾)。我会在调用codify() 之前推荐xor eax, eax,以便在将返回值存储在其中之前知道寄存器是干净的。
  • @BrendonBoldt 是的,谢谢你是对的,你能发表你的评论作为答案,以便我检查你的正确吗?
  • 你为什么pop eax ; restore eax?当然这只是为了重新平衡堆栈,因为下一次迭代在调用get5bitsFunc 破坏它之前不会读取它。所以指令是正确的,但评论完全错误/误导。同样,该调用之后的 POP 非常奇怪(并且弹出到内存中的速度比需要的慢)。此外,EDI 似乎没有被任何东西读取,所以这很奇怪。我假设你从你的真实代码中减少了这个。如果你在 inline-asm 中写这个来提高性能,你可能比优化编译器做得更糟......

标签: c visual-c++ assembly x86 inline-assembly


【解决方案1】:

Windows ABI 显然不需要函数返回 char 以零或符号将值扩展为 EAX,因此您需要假设 AL 上方的字节包含垃圾。 (这与the x86 and x86-64 System V ABI 中的相同。另请参阅 标记wiki 了解ABI/调用约定文档)。

您不能假设在调用 codify() 之前将 EAX 归零就足够了。在使用 AL 中的字符返回之前,可以免费使用所有 EAX 作为暂存寄存器,但其余部分则为垃圾EAX。

您实际上需要 movzx esi, al、(或 MOVSX)或 mov [mem], al 或其他任何您想做的事情来忽略高字节中的垃圾。

【讨论】:

    【解决方案2】:

    无符号字符只有 1 个字节,而 eax 是 32 位(4 字节)寄存器。如果 codify() 只返回 1 个字节,则返回值将存储在 aleax 的第一个字节)中,而 eax 的其余部分保持不变(这将导致垃圾)。我会在调用codify() 之前推荐xor eax, eax,这样您就可以在将返回值存储在其中之前知道该寄存器是干净的。

    【讨论】:

    • 正确的想法,错误的实现。在将其返回值留在 AL 中之前,codify 可以将整个 EAX 用作临时对象。 (我本来打算回复你对这个问题的评论,但后来我写的东西开始自己变成一个答案。很抱歉在你先发现问题后“偷走”你的答案。如果我会赞成这个答案您将建议固定为 XOR。)
    • 是的;我看你是对的。它只适用于不接触eax 的函数,除了返回。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-09
    • 2020-06-07
    • 2014-07-24
    • 1970-01-01
    • 1970-01-01
    • 2021-01-03
    • 1970-01-01
    相关资源
    最近更新 更多