On Tue, 2002/09/03 at 09:37:14 -0700, Peter Wemm wrote:
> Bernd Walter wrote:
> > On Tue, Sep 03, 2002 at 09:01:07AM -0700, Peter Wemm wrote:
> > I was running -current from 2002/08/11 before without any sign about
> > this kind of problem.
> > Building libiconv failed reproduceable for me, but booting an
> > 2002/08/11 kernel made me build the port.
> Yes, imgact_elf.c rev 1.121 is the culprit.  Reverting that change solves
> the problem.

I have attached a patch which, I believe, should fix the problem. I
have no alpha box, so I cannot test kernel patches beyond compiling
them, so be warned, all below is just a theory, and the patch might of
course be broken (so keep kernel.old around :). 

The problem was caused by the fact that on static executable, the text
segment is writable on alpha, so the heuristic prot & VM_PROT_WRITE in
the ELF image activator will regard everything as a data segment. This
has the (non-fatal) effect that the program text size is regarded to
be 0.

Much more fatal, however, is that obreak() assumes that all data
segments start on consecutive pages (see below). Newer binutils will
however place the data segment on the next 64k page at the same offset
after the text segment (probably to make it easier for the OS to use
super pages), so that holes of more than a page size can occur. 

obreak() will calculate the heap end address by taking the start
of the program data and adding the current data size.
The data size of a process is initially set by the image activator;
the ELF one sums up the number of 8k-pages actually needed to hold the
data. Now, if a "hole" happens to be between the segments that the
image activator thinks to hold data, (start address + number of used
pages) does of course not suffice to calculate the end address any

The result is that the vm_map_insert() in obreak() can collide with
program segments when trying to insert a mapping starting with the old
address (that was calculated incorrectly), so it will fail, causing
ENOMEM to be returned.

For dynamic executables, this does not occur because the text segment
is not writable; the dynamic section, which is writable and executable
(because of the plt) starts after the hole and is directly followed by
the rest of the data.

The attached patch does just change the heuristics used to detect
"text" segments to look for executable segments (using an idea from
Peter). This results in the fact that dynamic section is viewed as
text, which should not break anything.
This way, it should be possible to avoid the hole currently; a real
fix would be to add a new vmspace field to represent the heap size
including holes which could then be used by obreak(), while vm_dsize
would only be used for statistics (which is however difficult to
maintain when shrinking below the initial size with brk()).

Can somebody who is feeling adventurous and has an alpha box please
test whether this fixes it for now?

        - Thomas

Thomas Moestl <[EMAIL PROTECTED]> http://www.tu-bs.de/~y0015675/
              <[EMAIL PROTECTED]> http://people.FreeBSD.org/~tmm/
PGP fingerprint: 1C97 A604 2BD0 E492 51D0  9C0F 1FE6 4F1D 419C 776C

Index: kern/imgact_elf.c
RCS file: /home/ncvs/src/sys/kern/imgact_elf.c,v
retrieving revision 1.124
diff -u -r1.124 imgact_elf.c
--- kern/imgact_elf.c   2 Sep 2002 17:27:30 -0000       1.124
+++ kern/imgact_elf.c   3 Sep 2002 17:10:21 -0000
@@ -738,14 +738,14 @@
                         * to distinguish between the two for the purpose
                         * of limit checking and vmspace fields.
-                       if (prot & VM_PROT_WRITE) {
-                               data_size += seg_size;
-                               if (data_addr == 0)
-                                       data_addr = seg_addr;
-                       } else {
+                       if (prot & VM_PROT_EXECUTE) {
                                text_size += seg_size;
                                if (text_addr == 0)
                                        text_addr = seg_addr;
+                       } else {
+                               data_size += seg_size;
+                               if (data_addr == 0)
+                                       data_addr = seg_addr;

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message

Reply via email to