用汇编语言编写一个fopen函数

3

我正在尝试在Turbo C++ 3.0中实现fopen,我需要用asm inline编写它。

我写了一段代码,但是(毫不意外……)它没有起作用(编译失败)。

代码如下:

#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include <stdlib.h>

int my_fopen_w(char fname[])
{
    int fd;
    char status;
    status = 'w'; // I need to write to a file and delete previous content
    asm{
        mov bl, status
        xor bh,bh
        push bp
        mov bp, sp
        push bx
        push fname
        //Same as fopen now fopen(file path= fname, "w" = bx)
        call _fopen
        add sp,8

        // Returned value in AX register 
        mov fd, ax  // That line may be incorrect, my teacher demands an Integer returned value  

    }
    return fd;
}

我遇到了一个错误:Turbo C无法识别_fopen调用。

Error with "call _fopen"

调用fopen时出错 感谢任何帮助。

Haim


2
你需要在汇编代码的开头声明 _fopen 为全局对象(即在汇编代码开头添加 .global _fopen)。 - Ctx
3
为什么你要练习 MS DOS 的汇编语言编程? - Lundin
3
你的学校为何教你成为一个1990年代的程序员?你需要问他们为什么不教授实际能为你找到工作的技能。 - Lundin
2
现在这不是问题,我寻求帮助的原因并不重要,我练习汇编的目的就好。 - Haim
4
插入一个对 _fopen 函数的 C 调用,查看生成的汇编代码。也许,还有另一个下划线,你需要调用 __fopen 函数? - Holger
显示剩余13条评论
1个回答

2

这似乎是Turbo C 3.0中的一个bug。TCC 3.0默认将C库链接到CODE段,所以您可以使用函数地址(不需要下划线)将 AX 加载并使用 CALL AX

#include <stdio.h>

int main ( void )
{
    char fname[] = "noname.txt";
    char status[] = "wb";
    FILE * fd;
    asm{
        lea ax, status
        push ax
        lea ax, fname
        push ax

        lea ax, fopen
        call ax

        pop cx
        pop cx
        mov fd, ax
    }
    return 0;
}

请注意:fopen 需要两个字符串指针。这两个指针在编译时都是未知的。因此,您需要在运行时使用LEA来获取它们,除非其他人(操作系统、C启动代码等)已经为您获取了指针:
#include <stdio.h>

FILE*  my_fopen_w(char fname[])
{
    FILE * fd;
    char  status[]="wt";
    int my_fd;

    asm{
        lea ax, status
        push ax
        mov ax, fname               // fname was passed as a pointer ("Call by value")
        push ax

        lea ax, fopen
        call ax

        pop cx
        pop cx
        mov fd, ax
    }
    return fd;
}

int main(int argc, char *argv[])
{

  FILE * fd;

  fd = my_fopen_w(argv[1]);         // argv[1] is a pointer to a string
  fputs("Here I am.", fd);
  fclose(fd);

  return 0;

}

首先,非常感谢!!它确实通过了编译。但是在运行时它并没有工作.....我无法打开一个新文件,程序也没有显示错误,但文件并未创建! - Haim
2
@Haim - 如果rkhb的答案解决了你提出的问题,请考虑接受它(如果你想的话,也可以点赞)。至于你的代码为什么不起作用,那是因为你在某些地方使用了LEA,而应该使用MOV。这里提供了一个修订后可能有效的版本:capp-sysware.com/misc/stackoverflow/asmio.c - Michael Petch
谢谢谢谢谢谢!!!!!!它正在工作!!!!!!!!!!!!!!!!!!!!!!!谢谢!!!!你救了我的命!! - Haim
2
那么问题就在于Turbo C不允许像OP的第二个例子中那样调用call fopen,它显示了“无效的操作码和操作数组合”的屏幕截图?这很奇怪;也许它不知道如何进行rel16偏移,只能进行绝对偏移。顺便说一句,使用LEA而不是mov ax,offset fopen没有任何优势。对于[disp16]寻址模式,使用lea只会浪费一个字节的代码大小。但是,对于非静态数组,您确实需要lea:它们可能编译为lea ax,[bp-8]或其他内容,因为您创建了一个本地字符数组(将字符串字节复制到堆栈中),而不是一个static const - Peter Cordes
1
只是一点小提示。这个 bug 似乎只出现在 Turbo-C 的内部汇编器中。我同意 @PeterCordes 的观点,它似乎无法处理内联汇编中的相对调用。今天早上我碰巧遇到了这个问题,并注意到如果使用 TCC 3.0x 的 -B 选项进行编译,则可以正常工作。-B 将强制 TCC 输出一个汇编文件,然后调用 TASM 外部程序将文件汇编为对象文件(绕过内部汇编器)。使用 -B 看起来可以解决这个问题。 - Michael Petch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接