I am looking for an easy way to manage file opening and closing in x86-64 assembly on linux. I thought the easiest way would be to write a c file containing functions that I could call without having to worry about stability. So I wrote this function :
struct PORT open_port(char *filename, int mode) { struct PORT port; port.p = 0; if (mode) { if (filename == "stdout") port.f = stdout; else port.f = fopen(filename, "wb+"); } else { if (filename == "stdin") port.f = stdin; else port.f = fopen(filename, "rb"); } return port; }
And then I read the port like so:
char readchar(struct PORT *port) { char r; if ((*port).p) r = (*port).p; else r = fgetc((*port).f); (*port).p = 0; return r; }
Where PORT.p
is a char which contains the character at the current position and PORT.f
a file pointer. Then I call those function in my assembler code by putting the parameters in %rdi
and %rsi
.
Everything works as expected when I am reading an ordinary file, but the stdin
support doesn’t work. I know stdin
is supposed to be the value 0
and when I debug my code, I can see that the value holding the file pointer is indeed 0
, but when the code gets to the fgetc()
call, it seg faults. If I write plainly fgetc(0);
in my function, there is also a segmentation fault. I don’t get how the fgetc()
function can tell the difference between the stdin
and a normal 0
.
How can I read stdin
using this (or a very similar pattern)? Or if it’s all wrong, what should I do to open files in x64 assembly? There is certainly something I am not getting regarding how it works, help would be greatly appreciated.
(For those who are wondering what’s the point of this all: it’s to be able to read the next character without [in appearance] moving the file pointer, so there is a peekchar function that sets PORT.p
if it’s unset, so p
can hold the value until it’s read)
Advertisement
Answer
This was working when compiled with C, but not with the assembler code because of the wrong use of the ==
operator.
Since the C compiler only defined the string "stdin"
once, the string pointers where equal which made it look like it worked, but when calling it from the assembler code the pointer changed and the condition couldn’t be met.
Replacing ==
with strcmp()
solved it