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.
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.
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.
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.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 sacrificestdio
and use POSIX calls instead,stdin
is the same as the well-known file descriptor #0. You can therefore pass0
toread
and get almost what you were looking for. I'm pretty sure this is more assembler-friendly than thestdin
C macro.