Skip to content
Advertisement

Behavior of fgetc() function in C

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

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement