when running test application I encounter a new problem of dynamic linker
[init -> test-go] 0x1000000 .. 0x10ffffff: linker area [init -> test-go] Error: LD: symbol not found: '__data_start' [init -> test-go] Error: Uncaught exception of type 'Linker::Not_found'
any ideas how to fix?
seems that main binary test-go do have a weak ref to this symbol as nm show: w __data_start in some places of new code appeared after 10.3 gcc I found extern const char __data_start[] __attribute__ ((weak));
where I can add it, in what ld script?
Sincerely, Alexander
Hello Alexander,
On Sat, Jun 12, 2021 at 23:21:50 CEST, Alexander Tormasov via users wrote:
when running test application I encounter a new problem of dynamic linker
[init -> test-go] 0x1000000 .. 0x10ffffff: linker area [init -> test-go] Error: LD: symbol not found: '__data_start' [init -> test-go] Error: Uncaught exception of type 'Linker::Not_found'
any ideas how to fix?
seems that main binary test-go do have a weak ref to this symbol as nm show: w __data_start in some places of new code appeared after 10.3 gcc I found extern const char __data_start[] __attribute__ ((weak));
where I can add it, in what ld script?
The following patch adds the symbol right at the beginning of the data segment. I'm not certain that this is correct for your use case. Do you have any reference to an official documentation or source that specifies the use of this symbol?
repos/base/src/ld/genode.ld | 1 + repos/base/src/ld/genode_dyn.ld | 1 + 2 files changed, 2 insertions(+)
diff --git a/repos/base/src/ld/genode.ld b/repos/base/src/ld/genode.ld index db72891a67c..ef657a27278 100644 --- a/repos/base/src/ld/genode.ld +++ b/repos/base/src/ld/genode.ld @@ -54,6 +54,7 @@ SECTIONS
. = ALIGN(0x1000);
+ __data_start = .; .data : { /* * Leave space for parent capability parameters at start of data diff --git a/repos/base/src/ld/genode_dyn.ld b/repos/base/src/ld/genode_dyn.ld index 57ec92f0f6e..6913ada0479 100644 --- a/repos/base/src/ld/genode_dyn.ld +++ b/repos/base/src/ld/genode_dyn.ld @@ -109,6 +109,7 @@ SECTIONS * the same address within the page on the next page up. */ . = ALIGN(0x1000); + __data_start = .; .root_cap : { /* * Leave space for parent capability parameters at start of data
Regards
Hello Christian, thank you for a prompt respond!
in some places of new code appeared after 10.3 gcc I found extern const char __data_start[] __attribute__ ((weak));
where I can add it, in what ld script?
The following patch adds the symbol right at the beginning of the data segment. I'm not certain that this is correct for your use case. Do you have any reference to an official documentation or source that specifies the use of this symbol?
not sure that this is official, anyway, here https://gcc.gnu.org/wiki/Building_Cross_Toolchains_with_gcc?action=AttachFil... it mentioned as a part of default script: /* initialized data */ .init : AT (__text_end) { __data_start = .; *(.data) __data_end = .; } > ram
In general, golang start using it to perform tracing of code for debugging purposes, and add a special component called field track with the following comment:
/* The compiler will track fields that have the tag go:"track". Any function that refers to such a field will call this function with a string fieldtrack "package.type.field"
This function does not actually do anything. Instead, we gather the field tracking information by looking for strings of that form in the read-only data section. This is, of course, a horrible hack, but it's good enough for now. We can improve it, e.g., by a linker plugin, if this turns out to be useful. */
together with function to track end of code segment: // Return the end of the text segment, assumed to come after the // read-only data section.
uintptr getEtext(void) __asm__ (GOSYM_PREFIX "runtime.getEtext»);
uintptr getEtext(void) { const void *p;
p = __data_start; if (p == nil) p = __etext; if (p == nil) p = _etext; return (uintptr)(p); }
here another reference to ANSI C used in context that etext (another address to be defined) are the part of standard: https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_chapter/ld_3.html
In some cases, it is desirable for a linker script to define a symbol only if it is referenced, and only if it is not defined by any object included in the link. For example, traditional linkers defined the symbol `etext'. However, ANSI C requires that the user be able to use `etext' as a function name without encountering an error. The PROVIDE keyword may be used to define a symbol, such as `etext', only if it is referenced but not defined. The syntax is PROVIDE(symbol = expression).
in general, golang code reference to the following list of addresses related to ld script and position of code/etc: extern const char __etext[] __attribute__ ((weak)); extern const char __data_start[] __attribute__ ((weak)); extern const char __edata[] __attribute__ ((weak)); extern const char __bss_start[] __attribute__ ((weak));
some useful info I found in old IRIX man page http://polarhome.com/service/man/?qf=etext&tf=2&of=IRIX&sf=3
while they are obsolete, anyway, such symbols are created and used in modern linux as well.
my opinion that this is necessary component to be present by definition, and could be used for different tools and languages like golang. It is not mandatory (golang do not support it for AIX, while support for other 10 systems where it can run including *bsd, linux, solaris, windows/etc), but good to have them.
may be it worth to modify patch to add all of them, see above?
Sincerely Alexander
Alexander,
On Mon, Jun 14, 2021 at 15:22:37 CEST, Alexander Tormasov via users wrote:
uintptr getEtext(void) { const void *p;
p = __data_start; if (p == nil) p = __etext; if (p == nil) p = _etext; return (uintptr)(p); }
How do you think about the following fix in this cloudy situation?
1. Define __data_start to nil like it's done for _AIX
2. Accept __etext that is already provided by genode_dyn.ld
Greets
How do you think about the following fix in this cloudy situation?
- Define __data_start to nil like it's done for _AIX
this will allow compilation, anyway it drop features related to code tracing in go (new helpful debugging capability, as I understand)
- Accept __etext that is already provided by genode_dyn.ld
golang do not report any problems even before last patch, so, I assume that it accept current version (at least compile it)
so, seems that the best solution (safe, no changes in algorithms/data size/etc) seems to be to add these symbols to ldscript as proposed by previous patch.
Hello,
On 14.06.21 17:27, Alexander Tormasov via users wrote:
so, seems that the best solution (safe, no changes in algorithms/data size/etc) seems to be to add these symbols to ldscript as proposed by previous patch.
this conclusion is leading us nowhere.
Please consider adding whatever symbols you like to a linker script of your's and point the build system's LD_SCRIPT_DYN variable to your linker script. The hook is in place to accommodate situations like this. So please use it instead imposing changes on the default linker script.
Norman
Hello Norman, thanks for answer
On 14.06.21 17:27, Alexander Tormasov via users wrote:
so, seems that the best solution (safe, no changes in algorithms/data size/etc) seems to be to add these symbols to ldscript as proposed by previous patch.
this conclusion is leading us nowhere.
Please consider adding whatever symbols you like to a linker script of your's and point the build system's LD_SCRIPT_DYN variable to your linker script. The hook is in place to accommodate situations like this. So please use it instead imposing changes on the default linker script.
Sorry, I am not that familiar with ld scripts. I have a problem with LD_SCRIPT_DYN - I did not found how to use it. in short, if I set it inside my target.mk file to bulid application, like this: TARGET = test-go SRC_GO = main.go
LIBS = base libc libm libatomic libbacktrace libffi libgo libgo_support stdcxx
LD_SCRIPT_DYN = $(PRG_DIR)/my_genode_dyn.ld
CC_CXX_WARN_STRICT =
then it completely ignored, because prg.mk which do include target.mk in the very beginning, and later include global.mk which contain the following (which override it): # # Linker script for dynamically linked programs # LD_SCRIPT_DYN = $(BASE_DIR)/src/ld/genode_dyn.ld
while prg.mk contains the following lines later: # # Add a list of symbols that shall always be added to the dynsym section # LD_OPT += --dynamic-list=$(BASE_DIR)/src/ld/genode_dyn.dl
LD_SCRIPTS := $(LD_SCRIPT_DYN) LD_CMD += -Wl,--dynamic-linker=$(DYNAMIC_LINKER).lib.so \ -Wl,--eh-frame-hdr -Wl,-rpath-link=.
So, here, as you see, genode build system not only override it (I do not find any intermediate places to set it), but also unconditionally always add standard genode linker script via LD_OPT.
Finally it generate the following link command: genode-x86-g++ -Wl,-melf_x86_64 -Wl,-gc-sections -Wl,-z -Wl,max-page-size=0x1000 -Wl,--dynamic-list=/var/services/homes/admin/gen/21.05/repos/base/src/ld/genode_dyn.dl -nostdlib -Wl,-nostdlib -Wl,-Ttext=0x01000000 -m64 -mcmodel=large -Wl,--dynamic-linker=ld.lib.so -Wl,--eh-frame-hdr -Wl,-rpath-link=. -Wl,-T -Wl,/var/services/homes/admin/gen/21.05/repos/base/src/ld/genode_dyn.ld -Wl,--whole-archive -Wl,--start-group main.o $libs/base/base.lib.a $libs/libatomic/libatomic.lib.a $libs/libbacktrace/libbacktrace.lib.a $libs/libffi/libffi.lib.a $libs/libgo/libgo.lib.a $libs/libgo_support/libgo_support.lib.a ld.lib.so libc.lib.so libm.lib.so stdcxx.lib.so vfs.lib.so -Wl,--no-whole-archive -Wl,--end-group /var/services/homes/admin/gen/21.05/build/x86_64/var/libcache/base-linux-common/base-linux-common.lib.a /var/services/homes/admin/gen/21.05/build/x86_64/var/libcache/startup-linux/startup-linux.lib.a /var/services/homes/admin/gen/21.05/build/x86_64/var/libcache/cxx/cxx.lib.a /var/services/homes/admin/gen/21.05/build/x86_64/var/libcache/libc-stdlib/libc-stdlib.lib.a /var/services/homes/admin/gen/21.05/build/x86_64/var/libcache/libc-gen/libc-gen.lib.a /var/services/homes/admin/gen/21.05/build/x86_64/lib/libgo/libgobegin.a /var/services/homes/admin/gen/21.05/build/x86_64/lib/libgo/libgolibbegin.a /var/services/homes/admin/gen/21.05/build/x86_64/lib/libgo/.libs/libgo.a /usr/local/genode/tool/21.05/bin/../lib/gcc/x86_64-pc-elf/10.3.0/64/libgcc.a /usr/local/genode/tool/21.05/bin/../lib/gcc/x86_64-pc-elf/10.3.0/64/libgcc_eh.a -o test-go
And, I am not completely agree with your argument about modification of standard ld script. I understand your general approach of minimisation of changes and related support. Anyway, in short, - this modification is a part of standard gcc code/binutils, not related to golang (it just use it) - it does not take any resources like memory (just compilation alias) - it does not require any support afterward - it does not violate any security/etc approaches of genode and lower level OSes - if I move complete ld script for golang to world (may be I can just define only necessary name in add-on script?), then it will be necessary to support it (if main genode ld script will somehow evolve…).
Sincerely, Alexander
Hello Alexander,
in short, if I set it inside my target.mk file to bulid application, like this: TARGET = test-go SRC_GO = main.go
LIBS = base libc libm libatomic libbacktrace libffi libgo libgo_support stdcxx
LD_SCRIPT_DYN = $(PRG_DIR)/my_genode_dyn.ld
CC_CXX_WARN_STRICT =
then it completely ignored, because prg.mk which do include target.mk in the very beginning, and later include global.mk which contain the following (which override it): # # Linker script for dynamically linked programs # LD_SCRIPT_DYN = $(BASE_DIR)/src/ld/genode_dyn.ld
I'm very sorry that I overlooked that hard assignment. In commit [1] (on the staging branch), I changed it to a ?= assignment to make the variable customizable. Can you give it a try?
[1] https://github.com/genodelabs/genode/commit/5429c11ca8ad87465ebb017165764e77...
And, I am not completely agree with your argument about modification of standard ld script. I understand your general approach of minimisation of changes and related support. Anyway, in short,
- this modification is a part of standard gcc code/binutils, not related to golang (it just use it)
- it does not take any resources like memory (just compilation alias)
- it does not require any support afterward
- it does not violate any security/etc approaches of genode and lower level OSes
Global symbols of any kind are highly discouraged throughout Genode (see [2]) because they invite global side effects, which defeat the assessment of the correctness of programs. Symbol aliases are worse because they make the tracing of global side effects even more obscure. However hard I try, I cannot think of any legitimate use of a symbol that aliases the parent_cap symbol (at the beginning of the data segment). I can only think of illegitimate uses and the added risk of unintended information leakage.
[2] https://genodians.org/nfeske/2019-01-22-conscious-c++#Banning_hidden_state_a...
In fact, when I look at our linker script, I have the strong urge to *remove* several dubious symbols that stick out like sore thumbs. Adding more global symbols goes frontal against our grain.
The "part of standard" does not apply. The principles behind Genode are not at all aligned with what is commonly referred to as standard (POSIX). Mistakes should not be repeated, whether they are standard or not.
- if I move complete ld script for golang to world (may be I can just
define only necessary name in add-on script?), then it will be necessary to support it (if main genode ld script will somehow evolve…).
The burden of maintenance and responsibility always rests on someone's shoulders. When you ask us for adding global symbols to the default linker script on behalf of your single use case, you are actually asking us to take over responsibility and the commitment to carry forward (not break) this "feature" in the future. This may make your life more convenient while shifting the burden to us. In the worst case - should the feature turn out as a security disaster sometime later - we'd be responsible, not you. If a third party (e.g., for security evaluation) asks us for an explanation behind the content of the linker script, we must be able to give clear answers. Each addition is a liability. Hence, we are not eager to accept additional weight on our shoulders whenever we can avoid it.
In contrast, if you keep the customization of the linker script local to your program, Genode at large stays clear of any consequences.
Norman
I'm very sorry that I overlooked that hard assignment. In commit [1] (on the staging branch), I changed it to a ?= assignment to make the variable customizable. Can you give it a try?
what I have as command line after patch:
genode-x86-g++ -Wl,-melf_x86_64 -Wl,-gc-sections -Wl,-z -Wl,max-page-size=0x1000 -Wl,--dynamic-list=/var/services/homes/admin/gen/21.05/repos/base/src/ld/genode_dyn.dl -nostdlib -Wl,-nostdlib -Wl,-Ttext=0x01000000 -m64 -mcmodel=large -Wl,--dynamic-linker=ld.lib.so -Wl,--eh-frame-hdr -Wl,-rpath-link=. -Wl,-T -Wl,/var/services/homes/admin/gen/21.05/repos/world/src/test/go_app/genode_dyn.ld …
seems that this is ok, code start working again
and, I found another, simpler solution than usage of own script. I will add this line to lib/import/import-libgo_support.mk
LD_OPT += --defsym=__data_start=_parent_cap
which will efficiently define alias __data_start to already defined in ld script _parent_cap
Sincerely, Alexander