0

I'm faced with the problem of printing (in console) a value without using any library. I tried to do so by means of the returning value of main function but it seems that there is not a way to show in console the return value of a function without the use of printf(). I'm looking a piece of advice so feel free to 'brainstorm'. Any idea is welcomed, hope you can help me and thank you before hand.

1
  • Only possible with implementation provided functions. Commented Jun 9, 2021 at 4:38

2 Answers 2

2

Technically, write (note write and not fwrite) isn't a library function, it's a system call. stdout (which is what's going to appear on the screen), can be written to if you're able to find it's file descriptor number (hint hint, STDOUT_FILENO) using write.

Hope that's somewhat helpful! If you need some more direction feel free to drop a comment!

Sign up to request clarification or add additional context in comments.

4 Comments

Always nice to explain how the standard file descriptor numbers 0, 1, 2 are provided through the defined macros STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO. You hint at it, but always make clear the difference between a file descriptor and file stream pointer (e.g. FILE*). That said, you certainly provided him with good information to follow up on.
@David This is true, but it seems like this is a homework problem, so I figured I'd let them do a little digging after pointing them in the direction of the POSIX IO API ;)
No disagreement there, but adding the defines and numbers still leaves understanding the file descriptor use, the syscall use and validation (which can be daunting enough when the void* parameter to write() is encountered :)
You're right Mitchell, it's a homework problem. I'm gonna do some digging out there to figure out the solution but your info is pretty useful. Thanks!
2

Well "technically" what you call when you say write() is still "technically" in the standard library (although it may be some macro magic in .h files depending on your compiler). There are stub functions that call each system call.

"Technically" you'd need to know your ABI and you'd need to know how to invoke that ABI in your compiler. Then you'd need (generally, for most ABIs) what the current syscall number of write is and so on.

Looking it up, on linux (which isn't my home planet, but it has a chance of being yours) SYS_WRITE is syscall #1 on linux. You put that one in %rax, the fd in %rdi, the buffer pointer in %rsi and the count of characters in %rdx.

So here we go:

mov edx,4 ; message length mov ecx,msg ; message to write mov ebx,1 ; file descriptor (stdout) mov eax,4 ; system call number (sys_write) int 0x80 ; call kernel 

Those of you reading along at home might remember your BIOS saying something about INT 80 once-upon-a-time. It's the same INT 80.

Now you just need to get that assembly into your C file. Looks like with gcc you use asm

so ...

main() { __asm__("mov edx,4 ; message length" "mov ecx,msg ; message to write" "mov ebx,1 ; file descriptor (stdout)" "mov eax,4 ; system call number (sys_write)" "int 0x80 ; call kernel"); } 

Now... I'm not telling you here how to get your C string into the registers, but again, I'm saying "Technically" ...

NB: also, note that I've copied from two different examples here to show some code to make my point. The register names on X86 are a mess and I think the paragraph is using different naming conventions than the code snippet.

NB2: to be even more pedantic, "Technically" crt.o might be considered the standard library. It depends. Sometimes it's also a linker script. It's certainly something your compiler toolchain is providing you. I'm not going to copy it here, but for whatever platform you're interested in, google "smallest binary" or somesuch. Lots of people have done this sort of thing for their "channels" ...

9 Comments

This is an unsafe use of GCC's inline assembly; the compiler isn't expecting you to modify random registers without informing it. See stackoverflow.com/questions/5131568/… for how to do it correctly. I know it's just an illustration, but it's close enough to working that someone might actually try to use it.
Appreciate it, this was the sort of "brainstorming" that I was expecting. Have a good one!
Yeah... I realize that Nate. In a way, it wasn't part of the asked question. Probably wasn't even the answer the supplicant wanted, per se. I like going down rabbit holes. Barriers to this working: 1. doing what Nate said. Might not matter since main does nothing. I suppose main's return might be the syscall's return ... or gcc might stomp all over it. 2. you'll need to get the address of the string into the assembly msg symbol. Declaring it in assembly would do it. Declaring it as extern in C might do it.
3. it appears that gcc uses the "other" assembly syntax. Again "linux" and "gcc" are not my jam.
(heh... just reading the big posts about homework questions. I suppose this is me being a bit of a s**t disturber, too. If the professor had assigned this to me, I probably would have turned in a working version along the lines I spec'd. I probably would have tried to figure out how to get C to behave without crt.o (at least now --- I'm not sure I knew about crt.o in University (but I did know about syscalls)))
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.