How to call fgets in x86 assembly?

According to the documentation for fgets() , the function takes three parameters:

  • char * - a string that will contain input
  • int is an integer that represents the maximum number of characters to read
  • FILE * - a FILE * for the stream to be read from

I have no problem calling a function. I just push three parameters onto the stack, call the function and increase the ESP by 12.

My problem is with parameter number 3. What should be accepted as FILE * for standard input? In C, I can just use stdin , but I don't know what the equivalent is in x86 assembly.


Update: I am using NASM for Linux.

+4
source share
4 answers

The problem with stdin is that it is a macro that expands to the point that it not only depends on the platform, but it is most likely difficult to access from the assembly manually. If you are willing to sacrifice stdio and use POSIX calls instead, stdin matches the well-known file descriptor # 0. Therefore, you can pass 0 to read and get almost what you were looking for. I'm sure this is more suitable for assembler than the stdin C macro.

+5
source

If the assembly is a routine for C / C ++ code, most runtimes provide a means of directly accessing the stdin variable via an external link. Check out the stdio.h header file (or perhaps everything it includes). The usual suspects are variables with the name __stdin or an array FILE *, called something like __stdio[] , where the first 3 elements are stdin, stdout and stderr.

If C is used as a library for some other language (e.g. assembly), you need to call C runtime init first. This can be difficult to determine. If I had no idea how, I would write a hello world program and skip it with a debugger to see how it installs stdin .

Another completely different approach would be to call fopen() to get the FILE * file to read.

+1
source

stdin is a concept that exists only in C. Its definition depends on your compiler and C library, and because of macros, etc. It can be very difficult to call from assembler.

One thing you could try is to treat it as if stdin were a global variable-sized register. Load it into the register (using any name conventions used by your C compiler), and then push it onto the stack. If this does not work, you will need to study the C library source code to see how it does it.

Alternatively, you can use lower operating system calls, which might be more usable by assembler, however, since you did not specify your OS, it is difficult to be more specific.

0
source

This is a clean build using libc. - George Edison

Then the answer will depend entirely on the development system and operating system. Libc is not aimed at supporting this kind of thing.

Even if you could figure out how to do this, stdin points to a rather complicated OS or development-dependent FILE data structure that is initialized by libc using routines called before main () starts. Therefore, in a clean assembly, you will also need to do all this. Thus, the simple Hello World C language program makes a pretty good executable on any platform.

If you are writing a simple C program that reads some information from stdin, then parse it all and know exactly what it does, you will have a good start. But it will not be so fast, and what you learn, of course, will not be portable, say, from Visual Studio on Windows, to gcc on Linux.

0
source

All Articles