Other How does libc write work?

This question is about the internals of libc. As far as I understand, at some point, there has to be platform specific code for anything, so I am interested to see how
Code:
write
function works.

Edit - I removed part of my previous post as those questions are no longer relevant to me and the purpose of the post was also not clear. Now please see my second message in this thread to read the questions.
 
Thanks for the link, I have cloned the repository. I have a couple of questions related to code. Please have a look at lib/libc/sys/write.c for reference.

1) what is the reason we are using
Code:
 #pragma weak write

I have little experience with C, and have not seen this before. I found that this is called weak reference and that the linker does not complain if there is no definition for it. Question is why is it written here? Don't we define
Code:
write
just below that pragma? We do, so why is it there?

2) Do I understand it right?
Code:
write
is defined by delegating to
Code:
__sys_write
, which refers to
Code:
__write
? Where do I find code for it? I searched the whole tree and did not find anything, any hints? I only found something with this grep search ".*__write.*" in contrib. But I assume libc is compiled without that? I have also checked the Makefile, it is pretty big to carefully read every line, but I have not found anything that would seem to supply the definition of
Code:
__write
 
__weak_reference is a macro of assembly as defined in compat.h (in libc) for example.
This then ties to the #pragma.
See: https://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Weak-Pragmas.html
Weak just means you can override the write() with your own code and compiler won't barf.

Why is the __weak_reference done? So it can be overriden by virtual systems; files, ports, sockets etc. The .weak (pseudo) op makes that symbol (__write) available to all programs that link it. Perhaps some expect a system symbol of __write?
 
Last edited:
Well may be the case... may be the case that systemwise symbol is expected, but then how does it compile? I think I need to check the big Makefile
 
How does it compile? It's a reference. It just puts the symbol in the table and a link to write().
I think I've answered Question 1?
Question 2: No, you're not correct. It's a pseudo op. Look at the code:
C:
#define    __weak_reference(sym,alias)    \
.weak alias;.equ alias,sym
This is splattered all over FreeBSD kernel source and system/c libraries.

.equ is #define in assembly (at least if I recall correctly).

For example, /usr/src/sys/sys/cdefs.h defines it as such:
C:
#define    __weak_reference(sym,alias)    \
    __asm__(".weak alias");        \
__asm__(".equ alias, sym")

So your code snippet is __weak_reference(__sys_write,__write) says __write is over-writable with a user function called _write() and is an alias in the symbol table to the symbol __sys_write. No?
 
Okay, that part about weak referencing is clear; I initially tried to see the definition of write(), so it now turns out I need the definition of __sys_write. Clear. I have tried to find it, but I found only declarations, can you help me with this one?

The declarations are in interposing_table.c, if I recall correctly, it is in /lib/clib/sys/

Code:
#define    SLOT(a, b) \
[INTERPOS_##a] = (interpos_func_t)b

interpos_func_t __libc_interposing[INTERPOS_MAX] = {
...,
SLOT(write, __sys_write),
...}

Here I have a couple of questions. First is what does this syntax meant? Square brackets around an identifier, and then assignment, is it expanded in some way by the preprocessor? I understand that ## is concatenation of tokens, but it seems illegitimate C to have such a construct?
Code:
[] = something

And from what we have in interposing_table.c, it is not clear still where I can find the definition of this ?
Code:
__sys_write
If I do not see assembler definition of it, I cannot run it, right?
 
This is an array in C.

int A[30];

You can initialize the array ...

int A[30] = {1, 2, 3, ...

You'll need to learn C well to understand the code.
 
This is an array in C.

int A[30];

You can initialize the array ...

int A[30] = {1, 2, 3, ...

You'll need to learn C well to understand the code.
In your example you wrote "A", and then "[" after it, but what is written in interposing_table.c is "{https://en.wikipedia.org/wiki/Empty_string, aka string of length 0}" + "[", that is the difference. To be clear I am talking about this
Code:
#define    SLOT(a, b) \
[INTERPOS_##a] = (interpos_func_t)b

It expands to this
Code:
interpos_func_t __libc_interposing[INTERPOS_MAX] = {
...
[INTERPOS_write] = (interpos_func_t)__sys_write,
...

Okay I now see that interposing table is really meant to be taken from somewhere outside as it is declared external in libc/include/libc_private.c

Code:
typedef int (*interpos_func_t)(void);
interpos_func_t *__libc_interposing_slot(int interposno);
extern interpos_func_t __libc_interposing[] __hidden;
 
Okay, that part about weak referencing is clear; I initially tried to see the definition of write(), so it now turns out I need the definition of __sys_write. Clear. I have tried to find it, but I found only declarations, can you help me with this one?

The declarations are in interposing_table.c, if I recall correctly, it is in /lib/clib/sys/

Code:
#define    SLOT(a, b) \
[INTERPOS_##a] = (interpos_func_t)b

interpos_func_t __libc_interposing[INTERPOS_MAX] = {
...,
SLOT(write, __sys_write),
...}

Here I have a couple of questions. First is what does this syntax meant? Square brackets around an identifier, and then assignment, is it expanded in some way by the preprocessor? I understand that ## is concatenation of tokens, but it seems illegitimate C to have such a construct?
Code:
[] = something

This is standard C99 syntax for an array. As you correctly stated, ## equates to concatenation in the pre-processor.
All of the INTERPOS_???? are enums, defined in libc_private.h
So SLOT is called as SLOT(write, __sys_write) or SLOT(accept, __sys_accept) etc. depending on the type of interposition you're handling.

As unitrunker pointed out, they're elements in an array (hence the enum)

You probably want to read something about interposition: http://www2.eecs.berkeley.edu/Pubs/TechRpts/1996/CSD-96-920.pdf if you want to understand what it's attempting or are you purely focussed on __sys_write?
And from what we have in interposing_table.c, it is not clear still where I can find the definition of this ?
Code:
__sys_write
If I do not see assembler definition of it, I cannot run it, right?
Edit: I missed this bit.
Ok, the interposing_table.c contains the array of functions of __libc_interposing. Which one is called is defined by the macro INTERPOS_??? that is ultimately, after pre-processing, an enumerated type (an integer from 0 to nn - well actually that's not entirely true but in this circumstance it will suffice).
So, INTERPOS_accept is enum 0, which activates SLOT(accept, __sys_accept) and runs accept()
If you look in lib/libthr/thread/thr_syscalls.c in __thr_interpose_libc(void) you see an entire array of function calls where SLOT(accept); is expanded to:
C:
*(__libc_interposing_slot(INTERPOS_accept)) = (interpos_func_t)__thr_accept;
And so on.

I am not sure what your end goal is here? You want to know the "platform specific" part of write() but to what end?

By your own admission you're lacking in C knowledge (like most of us!), so you're on a steep learning curve understanding the nuances of C as implemented in the kernel and library. I would suggest that's not a good place to start.

But, don't let me dissuade you, I'm just pointing out reality. We can't learn unless we ask questions.
 
Okay, I got 2 things to say.

First, thanks for the link https://www2.eecs.berkeley.edu/Pubs/TechRpts/1996/CSD-96-920.pdf I just did not think of googling what interposition is;

second, my end goal is to understand platform specific code; see all of the utilities use write and read as something given to them for free, I just want to see how write is implemented on a typical x86 machine, to the point of looking at how it works with the registers, I know it is trivial, but I want to dig thru to it, so to speak, because then I will similarly go and read about how read works, or how creat works, do you understand? I will be able to compare this implementation of libc to other C libraries. That's the long time goal.

Short time goal is understand the definition if __sys_srite, yes. But ever shortest one is to read about interposition first :)
 
write(2) is not a function in the library. It is a system call. That should be obvious from a few hints: the man page section 2, and the top of the man page, which states very clearly: "WRITE(2) FreeBSD System Calls Manual". Which means it is implemented in the kernel. All you see in the source code of libc is a very thin adaptation layer that allows C code to call a system call directly.

If you want to find the actual write() implementation, you have to look in the kernel source. There it is a little complicated: the call first comes into the VFS layer, from where it is routed to multiple file and IO systems; the implementation of write() for UFS is different from ZFS is different from serial ports, and so on.

For learning the kernel, I wouldn't begin by reading the code itself, because the structure is a bit overwhelming. I would begin by reading the daemon book, also known as "Design and Implementation of the (Free)BSD operating system", Kirk McKusick is the main author. Get the up-to-date version (it's mostly black outside), get it autographed by Kirk, and read it. First time you can read it a little quickly. Second time, you need to pay careful attention to the IO chapters, where they go into the VFS layer and then the file system layer. Interesting coincidence: I was reading it again last night (due to the Coronovirus quarantine, I'm keeping somewhat strange hours), and I was in the UFS2 section of the book.

After reading *** AND UNDERSTANDING *** the book, then you read the source code. By that point, it would be useful to have knowledge of the C language, at the expert level.
 
write(2) is not a function in the library. It is a system call. That should be obvious from a few hints: the man page section 2, and the top of the man page, which states very clearly: "WRITE(2) FreeBSD System Calls Manual". Which means it is implemented in the kernel. All you see in the source code of libc is a very thin adaptation layer that allows C code to call a system call directly.

If you want to find the actual write() implementation, you have to look in the kernel source. There it is a little complicated: the call first comes into the VFS layer, from where it is routed to multiple file and IO systems; the implementation of write() for UFS is different from ZFS is different from serial ports, and so on.

For learning the kernel, I wouldn't begin by reading the code itself, because the structure is a bit overwhelming. I would begin by reading the daemon book, also known as "Design and Implementation of the (Free)BSD operating system", Kirk McKusick is the main author. Get the up-to-date version (it's mostly black outside), get it autographed by Kirk, and read it. First time you can read it a little quickly. Second time, you need to pay careful attention to the IO chapters, where they go into the VFS layer and then the file system layer. Interesting coincidence: I was reading it again last night (due to the Coronovirus quarantine, I'm keeping somewhat strange hours), and I was in the UFS2 section of the book.

After reading *** AND UNDERSTANDING *** the book, then you read the source code. By that point, it would be useful to have knowledge of the C language, at the expert level.

Wow, you cleared it out! Thanks a lot. And thanks to other participants of this discussion, your are veery helpful! unitrunker and mark_j
 
Here I have a couple of questions. First is what does this syntax meant? Square brackets around an identifier, and then assignment, is it expanded in some way by the preprocessor? I understand that ## is concatenation of tokens, but it seems illegitimate C to have such a construct?
Code:
[] = something
The name of that array syntax is Designated Initializers.
 
Back
Top