【问题标题】:x86 function returning char* in Cx86 函数在 C 中返回 char*
【发布时间】:2019-12-08 20:57:53
【问题描述】:

我想在 x86 中编写一个函数,该函数将从 C 程序中调用。
该函数应如下所示:

char *remnth(char *s, int n);

我希望它从字符串 s 中删除每个第 n 个字母并返回该字符串。这是我的 remnth.s 文件:

section.text
global remnth

remnth:
; prolog
    push ebp
    mov ebp, esp

; procedure
    mov eax, [ebp+8]; Text in which I'm removing every nth letter
    mov ebx, [ebp+12]; = n
    mov ecx, [ebp+8] ; pointer to next letter (replacement)


lopext:
    mov edi, [ebp+12]     ; edi = n  //setting counter
    dec edi               ; edi--  //we don't go form 'n' to '1' but from 'n-1' to '0'
lop1:
    mov cl, [ecx]         ; letter which will be a replacement
    mov byte [eax], cl    ; replace
    test cl,cl            ; was the replacement equal to 0?
    je exit               ; if yes that means the function is over
    inc eax               ; else increment pointer to letter which will be replaced
    inc ecx               ; increment pointer to letter which is a replacement
    dec edi               ; is it already nth number?
    jne lop1              ; if not then repeat the loop
    inc ecx               ; else skip that letter by proceeding to the next one
    jmp lopext            ; we need to set counter (edi) once more 

exit:
; epilog

    pop ebp     
    ret   

问题是,当我在 C 中从 main() 调用此函数时,出现分段错误(核心转储)

据我所知,这与指针高度相关,在这种情况下,我将返回 *char,并且由于我已经看到一些返回 int 的函数并且它们工作得很好,我怀疑我忘记了正确返回 *char 很重要。

这是我的 C 文件的样子:

#include <stdio.h>

extern char *remnth(char *s,int n);

int main()
{
    char txt[] = "some example text\0";

    printf("orginal = %s\n",txt);
    printf("after = %s\n",remnth(txt,3));

    return 0;
}

任何帮助将不胜感激。

【问题讨论】:

  • 您使用的是哪种 C 调用约定?上面的代码既不遵循 Microsoft 也不遵循 unix 约定。
  • @RaymondChen linux (unix),会不会是问题出在哪里?
  • 了解linux的寄存器保存规则。具体来说,您没有保留 ebx 或 edi。
  • 尝试一个更简单的程序,它只调用remnth 并将结果存储在一个变量中。然后查看调试器以单步执行该函数并查看返回的内容。 +1 给@TonyK。已经有一个计算机程序,其目的是获取 C 代码并将其转换为汇编。它被称为编译器。
  • 看起来你正在返回一个指向新字符串 end 的指针。这实际上是一件好事。调用者已经知道它在开始时传递了什么地址。所以这让它计算长度,例如将其传递给write 系统调用或其他显式长度使用。不要丢掉工作(比如找到长度); strcat 这样的 C 函数设计是一个糟糕的模型,它们很难有效地使用。

标签: c assembly x86 nasm inline-assembly


【解决方案1】:

您使用ecx 作为指针,cl 作为工作寄存器。由于clecx 的低8 位,因此您正在使用mov cl, [ecx] 指令破坏您的指针。您需要更改其中一个。通常,al/ax/eax/rax 用于临时工作寄存器,因为对累加器的某些访问使用较短的指令序列。如果您将al 用作工作寄存器,则应避免将eax 用作指针,而应使用不同的寄存器(请记住在必要时保留其内容)。

【讨论】:

  • 谢谢!尽管我正在研究寄存器是如何组织的,但我并没有意识到我犯了什么错误。我需要尽快变得不那么笨拙。
【解决方案2】:

需要在返回前将返回值加载到eax中。我假设你想返回一个指向字符串开头的指针,所以那是[ebp+8]

【讨论】:

  • 谢谢!我不知道为什么,但我以某种方式假设指向字符串开头的指针保存在eax 中。我完全忘记了我在增加它。
  • 返回一个指向新字符串end的指针其实是件好事;调用者已经知道它在开始时传递了什么地址。所以这让它计算长度,例如将其传递给write 系统调用或其他显式长度使用。不要丢掉工作(比如找到长度);像strcat 这样的C 函数设计是一个糟糕的模型,它们很难有效地使用。 strcpy() return value 解释了为什么 strcpy 是愚蠢的,而 stpcpy 更有意义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-27
  • 2012-02-18
  • 2018-09-03
  • 1970-01-01
  • 2023-02-16
  • 1970-01-01
  • 2010-09-27
相关资源
最近更新 更多