How to call fgets in x86 assembly?

2019-06-26 00:46发布

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

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

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

My problem is with parameter #3. What should be passed in as the 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'm using NASM on Linux.

4条回答
霸刀☆藐视天下
2楼-- · 2019-06-26 01:25

stdin is a concept which only exists in C. Its definition depends on your C compiler and library, and due to macros and the like, it may be very difficult to invoke from assembler.

One thing you could try is treating it as if stdin was a global variable of register size. Load it into a register (using whatever name mangling conventions your C compiler uses), then push it onto the stack. If this doesn't work, you'll need to examine the C library source code to see how it does things.

Alternately, you could use lower-level operating system calls that may be more amenable to assembler usage - however, since you didn't specify your OS, it's hard to be more specific.

查看更多
家丑人穷心不美
3楼-- · 2019-06-26 01:32

This is pure assembly making use of 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 kind of call, the stdin points to a fairly complex, OS- or development system-dependent FILE data structure which is initialized by libc using routines that are called before main() is run. So in pure assembly, you'd have to do all that, too. This kind of thing is why a simple C-language "Hello world" program makes a fairly good-sized executable on any platform.

If you write a simple C program that reads some info from stdin, and then disassemble the whole thing and understand exactly what it's doing, you'll have a good start on this. But it won't be quick to do this, and what you learn certainly won't be portable from, say, Visual Studio on Windows to gcc on Linux.

查看更多
霸刀☆藐视天下
4楼-- · 2019-06-26 01:36

If the assembly is a subroutine to C/C++ code, most runtime environments provide a means of directly accessing the stdin variable through an external reference. Check the stdio.h header file (or maybe whatever it includes). The usual suspects seem to be variables named __stdin or an array of FILE * named something like __stdio[] where the first 3 elements are stdin, stdout, and stderr.

If C is being used as a library for some other language (like assembly), then you'll have to call the C runtime init yourself. That can be tricky to identify. If I had no idea how, I'd write a "hello world" type C program and step through it with a debugger to see how it sets up stdin.

Another completely different approach would be to call fopen() to obtain a FILE * of a file to read.

查看更多
▲ chillily
5楼-- · 2019-06-26 01:44

The problem with stdin is that it's a macro that expands to something not only platform-specific, but most likely difficult to access from assembly by hand. If you're willing to sacrifice stdio and use POSIX calls instead, stdin is the same as the well-known file descriptor #0. You can therefore pass 0 to read and get almost what you were looking for. I'm pretty sure this is more assembler-friendly than the stdin C macro.

查看更多
登录 后发表回答