This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC] Avoiding _divsi3 call during ld.so bootstrap


I am working on getting the Xtensa port of glibc updated to contribute to libc-ports, and we have run into an issue that would be easiest to address in the main libc files. I'd appreciate some guidance about whether a patch would be acceptable or whether I ought to pursue some sort of workaround.

The following line in elf_dynamic_do_rel in elf/do-rel.h is generating a call to _divsi3:

r = r + MIN (nrelative, relsize / sizeof (ElfW(Rel)));

Xtensa uses RELA relocations so this is a divide by 12, which can't be optimized to a simple right shift, and most Xtensa processors don't have a divide instruction. During ld.so bootstrap, this call fails because the address of _divsi3 comes from the GOT, which has not yet been relocated.

Here are the solutions I've thought of so far:

Option 1) Patch the code to avoid the division. The pointer addition will multiply the addend by the element size, and the multiplication and division cancel out. This patch pushes the multiplication into the first operand of MIN so the second operand doesn't require a division. I believe this patch has been used in MontaVista's glibc on multiple platforms for several years. It does make the code a bit hard to read, though.

diff -u -r1.33 do-rel.h
--- elf/do-rel.h 24 Sep 2004 17:09:03 -0000 1.33
+++ elf/do-rel.h 4 Apr 2007 18:10:15 -0000
@@ -76,7 +76,8 @@
ElfW(Word) nrelative = (map->l_info[RELCOUNT_IDX] == NULL
? 0 : map->l_info[RELCOUNT_IDX]- >d_un.d_val);
const ElfW(Rel) *relative = r;
- r = r + MIN (nrelative, relsize / sizeof (ElfW(Rel)));
+ r = (const ElfW(Rel) *)((const char *) r
+ + MIN (nrelative * sizeof (ElfW(Rel)), relsize));
#ifndef RTLD_BOOTSTRAP
/* This is defined in rtld.c, but nowhere in the static libc.a; make



Option 2) Patch the code differently. The division was introduced in 2002 to fix an overflow problem: http://sources.redhat.com/ml/libc- alpha/2002-06/msg00150.html. If I understand the situation correctly, if relsize is zero, the reladdr value may be uninitialized, and if it has a large value, an overflow may occur. The following patch reverts the previous change but guards the assignment by a check for relsize == 0. I haven't tested it at all yet, but I thought I would suggest it since it's much more readable than the previous version.


diff -u -r1.33 do-rel.h
--- elf/do-rel.h 24 Sep 2004 17:09:03 -0000 1.33
+++ elf/do-rel.h 4 Apr 2007 18:14:32 -0000
@@ -76,7 +76,8 @@
ElfW(Word) nrelative = (map->l_info[RELCOUNT_IDX] == NULL
? 0 : map->l_info[RELCOUNT_IDX]- >d_un.d_val);
const ElfW(Rel) *relative = r;
- r = r + MIN (nrelative, relsize / sizeof (ElfW(Rel)));
+ if (relsize != 0)
+ r = MIN (r + nrelative, end);
#ifndef RTLD_BOOTSTRAP
/* This is defined in rtld.c, but nowhere in the static libc.a; make



Option 3) Find some workaround in the Xtensa toolchain. We figured this issue must come up for other platforms without divide instructions. The one platform we looked at (ARM) appeared to use a PC-relative call to _divsi3 that didn't require any dynamic relocations. That won't work in general on Xtensa because the PC- relative call instructions have a limited range, but perhaps I could add some special command-line option to GCC so we can do it for this particular file (assuming that _divsi3 ends up within range, otherwise more hacks would be needed). Or, even worse, we could try to always generate in-line code for division by 12!


Opinions?

--Bob


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]