Page 1 of 1

[solved] Newlib errno issues

Posted: Tue Oct 18, 2011 1:01 am
by RobertF
I've been having issues with errno: it refuses to set. Originally when trying to access errno, I would page fault. I discovered that it was because I was not mapping it when I parsed the ELF. Now I can access it just fine, but even using all the minimal implementations of the system calls for newlib appears to not set errno. Another thing I've noticed is that it will work properly if I set errno within my program (which seems obvious that it would), but just not when being set in _read(), _write(), etc.

I'm unsure of what information I'd need to provide here, so I'll update this post as more info is required.

Re: Newlib errno issues

Posted: Tue Oct 18, 2011 1:14 am
by Solar
Check out the errno.h header, and find out what the implementation of errno actually is. It might rely on some internal workings, some memory area set up or something like that. Without looking at the source, it's hard to say.

Re: Newlib errno issues

Posted: Thu Oct 20, 2011 5:21 am
by jal
For example, the errno on a random Linux box I just checked is defined as:

Code: Select all

#   define errno (*__errno_location ())
So you cannot really assign that a value.

EDIT: I see that the wiki page on porting Newlib does an undef and then uses the global errno.


JAL

Re: Newlib errno issues

Posted: Thu Oct 20, 2011 5:41 am
by Solar
jal wrote:For example, the errno on a random Linux box I just checked is defined as:

Code: Select all

#   define errno (*__errno_location ())
So you cannot really assign that a value.
Of course you can. __errno_location() returns a pointer to the location of errno, which is then dereferenced to yield the expected integer.

The point being that __errno_location() is at liberty to return different values, e.g. for different threads. But of course you can assign values to it. Without the ability to errno = 0, the whole mechanism would be rather pointless, wouldn't it?

Re: Newlib errno issues

Posted: Thu Oct 20, 2011 5:56 am
by jal
Solar wrote:But of course you can assign values to it. Without the ability to errno = 0, the whole mechanism would be rather pointless, wouldn't it?
Indeed, I don't know what I was thinking... Induced by sleep deprivation, probably...


JAL

Re: Newlib errno issues

Posted: Thu Oct 20, 2011 8:24 am
by RobertF
Apparently I wasn't mapping data from the .data section header correctly—now errno reads properly, but only when it isn't redefined as an extern int.

Re: Newlib errno issues

Posted: Thu Oct 20, 2011 8:38 am
by Solar
Might be that some part of the newlib code messes with the internals of __errno_location() directly and doesn't like having errno redefined. (Might be worth a find / grep. ;-) )

Re: Newlib errno issues

Posted: Mon Oct 24, 2011 2:42 pm
by Owen
"extern int errno" is undefined behavior per C88/C99/C1X. That said, it is sometimes used in old (pre-threads) Unix software, so if you intend to be Unix compatible may prove useful to implement (make the "errno" symbol refer to the errno value for the "main" thread)

Re: [solved] Newlib errno issues

Posted: Tue May 08, 2012 2:38 pm
by Whitebird
Hi,

I decided to take advantage of this old post to ask a similar question that might be stupid but I'm stuck on it.

I did't get how to implement the errno variable. I mean: do I need to have a file "errno.c", which is linked with the kernel?
How do I handle with errno references declared in "user programs"? Whenever an executable is loaded, I must resolve this "external references" looking for errno references in the symbols table and then linking them with the kernel variable?

Thanks in advance.

Re: [solved] Newlib errno issues

Posted: Tue May 08, 2012 4:01 pm
by gerryg400
Whitebird wrote:Hi,

I decided to take advantage of this old post to ask a similar question that might be stupid but I'm stuck on it.

I did't get how to implement the errno variable. I mean: do I need to have a file "errno.c", which is linked with the kernel?
How do I handle with errno references declared in "user programs"? Whenever an executable is loaded, I must resolve this "external references" looking for errno references in the symbols table and then linking them with the kernel variable?

Thanks in advance.
Firstly, errno is a user-space variable. It should be linked into the c library. It's best if the kernel never touches it and the variable is managed by your c library. There are a few ways to do this. I do it like this. If the kernel returns a negative number from a system call then that is an error and the absolute value of the return value is the error number.

Code: Select all

ssize_t read(int fildes, void *buf, size_t nbyte) {

    ssize_t     ret;

    if ((ret = anvil_read(fildes, buf, nbyte, -1)) < 0) {
        errno = -ret;
        return -1;
    }

    return ret;
}

Re: [solved] Newlib errno issues

Posted: Wed May 09, 2012 2:50 am
by Whitebird
Thanks for the quick response gerryg400! I really need this tip. It helped me a lot.

Cheers,


Whitebird

Re: [solved] Newlib errno issues

Posted: Wed May 09, 2012 3:50 am
by Solar
gerryg400 wrote:It's best if the kernel never touches it and the variable is managed by your c library.
One point I came to realize while working on the PDCLib, more exactly, Plaugher's excellent book on the subject. The reason for this indirection...
#define errno (*__errno_location ())
...is that this allows the library to defer setting errno to when (and if) it is actually read (i.e., the function __errno_location() is actually being called).

It is not obvious why this would be necessary for stuff like I/O, where errno is set in direct response to something the kernel does, but (according to Plaugher, haven't tested it myself yet) it makes a world of difference for the math functions. Consider your C library using FPU functionality to implement those. Now consider what would be necessary if errno were simply defined to be an integer somewhere in memory. You would have to read out the FPU status flag after every math function. There goes your performance...

With the above mechanism, you need to read the FPU status flag only if errno were actually accessed.