Discussion:
[OpenRISC] newlib linking error: __getreent defined twice
Christian Svensson
2014-07-03 21:04:08 UTC
Permalink
Hi,

I'm playing with newlib. I'm using https://github.com/openrisc/or1k-src/
and I'm compiling it like this:
EXTRA_BINUTILS=--disable-werror
(cd ${BUILDDIR}/build-or1k-newlib && \
${SRCDIR}/newlib/or1k-src/configure --target=${TARGET}
--prefix=/srv/compilers/openrisc-devel \
--disable-shared --disable-itcl --disable-tk --disable-tcl
--disable-winsup \
--disable-libgui --disable-rda --disable-sid --disable-sim
--disable-gdb \
--with-sysroot --enable-newlib --enable-libgloss
${EXTRA_BINUTILS} && \
make ${MAKEOPTS

I have this code:
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>

extern int _board_clk_freq;

void finish_test(const char *fmt, ...) {
va_list arg_list;
va_start(arg_list, fmt);
vprintf(fmt, arg_list);
va_end(arg_list);
fflush(stdout);
}

int main(int argc, char *argv[]) {
finish_test("%d MHz", _board_clk_freq / (1000*1000));
return 0;
}

Compiling results in the following:
or1k-elf-gcc vprintf.c
/srv/compilers/openrisc-devel/lib/gcc/or1k-elf/4.9.0/../../../../or1k-elf/lib/libc.a(lib_a-or1k-impure.o):
In function `__getreent':
/home/bluecmd/or1k-devel/newlib/../newlib/or1k-src/newlib/libc/machine/or1k/or1k-impure.c:80:
multiple definition of `__getreent'
/srv/compilers/openrisc-devel/lib/gcc/or1k-elf/4.9.0/../../../../or1k-elf/lib/libc.a(lib_a-getreent.o):/home/bluecmd/or1k-devel/newlib/../newlib/or1k-src/newlib/libc/reent/getreent.c:13:
first defined here
collect2: error: ld returned 1 exit status

Masking newlib/libc/reent/getreent.c with #if 0 (so the only definition is
or1k-impure.c) makes it work just fine.
diff --git a/newlib/libc/reent/getreent.c b/newlib/libc/reent/getreent.c
index 60ae6fb..d85d654 100644
--- a/newlib/libc/reent/getreent.c
+++ b/newlib/libc/reent/getreent.c
@@ -1,5 +1,6 @@
/* default reentrant pointer when multithread enabled */

+#if 0
#include <_ansi.h>
#include <reent.h>

@@ -12,3 +13,4 @@ _DEFUN_VOID(__getreent)
{
return _impure_ptr;
}
+#endif

Obviously that is not a correct solution though :-).

Ideas?
Peter Gavin
2014-07-03 21:49:24 UTC
Permalink
Post by Christian Svensson
or1k-elf-gcc vprintf.c
multiple definition of `__getreent'
first defined here
collect2: error: ld returned 1 exit status
Masking newlib/libc/reent/getreent.c with #if 0 (so the only definition is
or1k-impure.c) makes it work just fine.
diff --git a/newlib/libc/reent/getreent.c b/newlib/libc/reent/getreent.c
index 60ae6fb..d85d654 100644
--- a/newlib/libc/reent/getreent.c
+++ b/newlib/libc/reent/getreent.c
@@ -1,5 +1,6 @@
/* default reentrant pointer when multithread enabled */
+#if 0
#include <_ansi.h>
#include <reent.h>
@@ -12,3 +13,4 @@ _DEFUN_VOID(__getreent)
{
return _impure_ptr;
}
+#endif
Obviously that is not a correct solution though :-).
Ideas?
It seems to me the simplest solution would be to remove the definition of
getreent from or1k-impure.c, and swap the roles of __current_impure_ptr and
__impure_ptr. Something like this:

====== BEGIN DIFF ========
diff --git a/newlib/libc/machine/or1k/or1k-impure.c
b/newlib/libc/machine/or1k/or1k-impure.c
index 4b47cf9..6dbfcb1 100644
--- a/newlib/libc/machine/or1k/or1k-impure.c
__impure_init (void)
{
// Initialize both impure data structures
- _REENT_INIT_PTR (_impure_ptr);
+ _REENT_INIT_PTR (_current_impure_ptr);
_REENT_INIT_PTR (_exception_impure_ptr);

- // Set current to standard impure pointer
- _current_impure_ptr = _impure_ptr;
+ // Set standard impure pointer to current
+ _impure_ptr = _current_impure_ptr;
} /* __impure_init () */
-
-struct _reent * __getreent(void) {
- // Return the current one. This is set initially above, and during
runtime
- // at or1k_exception_handler
- return _current_impure_ptr;
-}
diff --git a/newlib/libc/machine/or1k/or1k-support-asm.S
b/newlib/libc/machine/or1k/or1k-support-asm.S
index 78e29cc..532a5a5 100644
--- a/newlib/libc/machine/or1k/or1k-support-asm.S
+++ b/newlib/libc/machine/or1k/or1k-support-asm.S
@@ -627,12 +627,20 @@ or1k_exception_handler:
l.sw 0x70(r1), r30
l.sw 0x74(r1), r31

+ /* Save impure pointer for exception */
+ l.movhi r20, hi(_impure_ptr)
+ l.ori r20, r20, lo(_impure_ptr)
+ l.lwz r20, 0(r20)
+ l.movhi r21, hi(_current_impure_ptr)
+ l.ori r21, r21, lo(_current_impure_ptr)
+ l.sw 0(r21), r20
+
/* Replace impure pointer for exception */
l.movhi r20, hi(_exception_impure_ptr)
l.ori r20, r20, lo(_exception_impure_ptr)
l.lwz r20, 0(r20)
- l.movhi r21, hi(_current_impure_ptr)
- l.ori r21, r21, lo(_current_impure_ptr)
+ l.movhi r21, hi(_impure_ptr)
+ l.ori r21, r21, lo(_impure_ptr)
l.sw 0(r21), r20

/* Determine offset in table of exception handler using r3*/
@@ -663,11 +671,11 @@ or1k_exception_handler:
)

/* Restore impure pointer */
- l.movhi r20, hi(_impure_ptr)
- l.ori r20, r20, lo(_impure_ptr)
+ l.movhi r20, hi(_current_impure_ptr)
+ l.ori r20, r20, lo(_current_impure_ptr)
l.lwz r20, 0(r20)
- l.movhi r21, hi(_current_impure_ptr)
- l.ori r21, r21, lo(_current_impure_ptr)
+ l.movhi r21, hi(_impure_ptr)
+ l.ori r21, r21, lo(_impure_ptr)
l.sw 0(r21), r20

/* Restore state */
====== END DIFF ========

I also added a bit of code to save __impure_ptr to __current_impure_ptr at
the start, because it wasn't being saved, which didn't make sense to me.

I haven't tested this change, YMMV :)

-Pete
Stefan Wallentowitz
2014-07-04 06:49:03 UTC
Permalink
Post by Peter Gavin
It seems to me the simplest solution would be to remove the definition
of getreent from or1k-impure.c, and swap the roles of
[..]
I also added a bit of code to save __impure_ptr to
__current_impure_ptr at the start, because it wasn't being saved,
which didn't make sense to me.
I haven't tested this change, YMMV :)
-Pete
Hi,

yes, that is the straight forward way for the standard toolchain. The
reason I solved it that way was that the change to multicore is much
easier then (see the multicore branch). For the moment we should change
it back to use _impure_ptr as long as I search for the proper way to
work with getreent (Although it seems commenting it out is the way to go..)

Bye,
Stefan
Stefan Wallentowitz
2014-07-04 06:43:25 UTC
Permalink
Post by Christian Svensson
Obviously that is not a correct solution though :-).
Ideas?
Hi Christian,

I also encountered this for the multicore case and wanted to discuss
this with you then. I was not aware the problem also occurs for the
normal toolchain :(
I read nearly all occurences of the getreent stuff for newlib and came
to the solution (and also saw a post of the newlib guy) that your
solution seems to be the recommended way as long as you don't have a sys
folder.

I will write down what I found and how this might be done asap.

Bye,
Stefan
Stefan Wallentowitz
2014-07-04 06:50:26 UTC
Permalink
Post by Christian Svensson
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
extern int _board_clk_freq;
void finish_test(const char *fmt, ...) {
va_list arg_list;
va_start(arg_list, fmt);
vprintf(fmt, arg_list);
va_end(arg_list);
fflush(stdout);
}
Maybe noteworthy: The problem comes with linking if user code has va_*
or assert (thats what I observed in the multicore branch).

Bye,
Stefan

Loading...