TL-DR: How can I access the `stdin` symbol from stdio.h?
I know that QBE can interface with C, as in my language, this code
```elle
fn input(String message) {
String out = “";
puts(message);
scanf!("%s", out);
ret out;
}
pub fn main() {
String res = input("input pls?\n”);
printf!("\ndid you say %s? that's so true\n", res);
}
```
compiles to this IL
```qbe
function l $input(l %message_1) {
@start
%out_2 =l copy $input_3
%tmp_4 =w call $puts(l %message_1)
%tmp_6 =w call $scanf(l $input_5, ..., l %out_2)
%r_v6_7 =l copy %out_2
ret %r_v6_7
}
export function w $main() {
@start
%tmp_10 =l call $input(l $main_9)
%res_8 =l copy %tmp_10
%tmp_12 =w call $printf(l $main_11, ..., l %res_8)
ret
}
data $input_3 = { b "", b 0 }
data $input_5 = { b "%s", b 0 }
data $main_9 = { b "input pls?\n", b 0 }
data $main_11 = { b "\ndid you say %s? that's so true\n", b 0 }
```
which runs fine. As %out_2 is a pointer, passing it to `scanf` works. However, I would like to use `fgets` instead, as `scanf` doesn’t particularly handle strings with whitespace very well. The issue is that I’m not sure how to access the stdin file pointer from stdio.h, and as Elle cannot currently create opaque types I’m stuck on how to manually implement an stdin file pointer to pass to `fgets` without segfaulting.
I, of course, did try to think logically and see if `stdin` would just be a symbol defined with a global sigil, but it isn’t.
Thank you,
Rosie
> I, of course, did try to think logically and see if `stdin` would
just be a symbol defined with a global sigil, but it isn’t.
Are you perhaps running on Windows?
I've had a similar problem.
On Windows, `stdin` is defined as such:
extern FILE _iob[];
#define stdin (&_iob[0])
You would have to call `fgets` like so:
%out_2 =l copy $input_3
%stdin =l copy $_iob
%stdin =l add $_iob, 0 # = 0 * sizeof(FILE*)
%result =l call $fgets(l %out_2, w 2, l %stdin)
On Linux, `stdin` is simply defined as a pointer:
$ grep stdin /usr/include/stdio.h
extern FILE *stdin; /* Standard input stream. */
#define stdin stdin
You should therefore be able to do:
%out_2 =l copy $input_3
%result =l call $fgets(l %out_2, w 2, l $stdin)
> data $input_3 = { b "", b 0 }
Note here that your `$input_3` only has space for two bytes.
That might be one reason for a segfault.
> The issue is that I’m not sure how to access the stdin file pointer
from stdio.h, and as Elle cannot currently create opaque types I’m stuck
on how to manually implement an stdin file pointer to pass to `fgets`
without segfaulting.
There is no need to declare `$stdin` anywhere in QBE (assuming it exists).
Oh, and for MacOS, seems like the symbol is named `__stdinp`:
$ grep stdin
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/stdio.h
extern FILE *__stdinp;
#define stdin __stdinp
On Mon, 22 Apr 2024 20:58:34 +0100
Rosie Acquite <acquitefx@gmail.com> wrote:
> I, of course, did try to think logically and see if `stdin` would just be a symbol defined with a global sigil, but it isn’t.
you'll need to read the platform headers,
and generate code accordingly; the code
will be platform specific.
you'll need to do this platform specific
stuff for a few other things, like the
definition of various structs.
--
Ori Bernstein <ori@eigenstate.org>
> you'll need to read the platform headers,
> and generate code accordingly; the code
> will be platform specific.
Thank you! I'll keep this in mind.
> Oh, and for MacOS, seems like the symbol is named `__stdinp`:
I seems this fails to compile
I'm trying to compile this
```qbe
export function w $main() {
@start
%out_2 =l copy $input_3
%result =l call $fgets(l %out_2, w 1, l $__stdinp)
%tmp_12 =w call $printf(l $main_11, ..., l %out_2)
ret
}
data $input_3 = { b 0 }
data $main_11 = { b "%s\n", b 0 }
```
It fails with
```out
final section layout:
__TEXT/__text addr=0x100003F48, size=0x00000058,
fileOffset=0x00003F48, type=1
__TEXT/__stubs addr=0x100003FA0, size=0x00000018,
fileOffset=0x00003FA0, type=29
__TEXT/__unwind_info addr=0x100003FB8, size=0x00000048,
fileOffset=0x00003FB8, type=22
__DATA_CONST/__got addr=0x100004000, size=0x00000010,
fileOffset=0x00004000, type=31
__DATA/__data addr=0x100008000, size=0x00000030,
fileOffset=0x00008000, type=0
ld: ARM64 ADRP out of range (-4294979584 max is +/-4GB): from _main
(0x100003F48) to ___stdinp@0x00000000 (0x00000000) in '_main' from out.o
for architecture arm64
```
I believe this means that the __stdinp pointer address is 0x00000000,
which is incorrect?