Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 03 Jul 1999 22:55:07 +0800
From:      Peter Wemm <peter@netplex.com.au>
To:        Jason Evans <jasone@canonware.com>
Cc:        current@freebsd.org
Subject:   Re: mmap(), MAP_STACK, and safe addresses 
Message-ID:  <19990703145507.A4BD564@overcee.netplex.com.au>
In-Reply-To: Your message of "Fri, 02 Jul 1999 22:55:12 MST." <Pine.BSF.4.05.9907021955010.19167-100000@sturm.canonware.com> 

next in thread | previous in thread | raw e-mail | index | archive | help
Jason Evans wrote:
> I need a clue about process memory layout, and am hoping someone can
> provide it.  I wrote a program to discover what address ranges mmap() can
> handle (trying to hack growable stacks into libc_r), and came up with the
> following output (annotations in `[]'):
> 
> ----
> FreeBSD donner 4.0-CURRENT FreeBSD 4.0-CURRENT #2: Fri Jul  2 19:25:07
> PDT 1999     toor@donner:/usr/src/sys/compile/CUSTOM_donner  i386
>    text    data     bss     dec     hex filename
>    2464     220     272    2956     b8c ./brute_stack
> initialized global:   0x08049a90
> uninitialized global: 0x08049c74
> main() function:      0x08048604
> main() stack:        ~0xbfbfd90c (grows down)
> stack size: 0x1000 bytes
> bad:  0x00000000 --> 0x00000fff, 0x00001000 bytes
> good: 0x00001000 --> 0x08047fff, 0x08047000 bytes [???]
> bad:  0x08048000 --> 0x280e3fff, 0x2009c000 bytes [text->data->bss->heap->]
> good: 0x280e4000 --> 0xbfbddfff, 0x97afa000 bytes [-><-]                   
> bad:  0xbfbde000 --> 0xffffffff, 0x40422000 bytes [<-stack, env]           
> malloc()ed stack: 0x0804b000
> ----
> 
> Some questions about the above:
> 
> 1) What is the ??? range for?  (The loader?)

Under ELF, the program load address is 0x08048000.  Why?  Good question -
"because it is". :-)

> 2) Where exactly is the stack on the x86?

0xbfbddfff, growing down.  User addressable space (ie: the limit on the
%cs and %ds segments) ends there, a user cannot address beyond there.

0xbfbde000 through 0xbfbdffff are where the upages would have been if they
still existed.  The space is still reserved since there is a virtual
redirection there for libkvm and gdb to read the upages from via the procfs
'mem' file.

0xbfbe0000 through 0xbfffffff are the page tables, page directories etc.
0xc0000000 onwards is kernel space.

You can also get info from the map file in procfs:

Format: start, end, resident, private resident, vm object, access, refcnt,
shadowcount, flags, cow, needs-copy, pager type.

peter@overcee[10:35pm]~src/sys/nfs-118> cat /proc/curproc/map
0x08048000 0x08054000 12 13 0xc6bb45e8 r-x 2 1 0x0 COW NC vnode
0x08054000 0x08055000 1 0 0xc6d50d80 rw- 1 0 0x2180 COW NNC vnode
0x08055000 0x08059000 3 0 0xc6c67510 rw- 2 0 0x2180 NCOW NNC default
0x08059000 0x0806a000 2 0 0xc6c67510 rwx 2 0 0x2180 NCOW NNC default
0x28054000 0x28055000 1 0 0xc6ba2af8 rwx 1 0 0x2180 NCOW NNC default
0xbfbde000 0xbfbfe000 1 0 0xc6c8b6c0 rwx 1 0 0x2180 NCOW NNC default

COW = copy-on-write, NCOW = not copy on write.  NC = needs copy, NNC = not
needs copy.

In this case, the stack is in the last segment and is a whole one page.

> 3) Where is the stack on the Alpha?

Umm...

pwroot@ashburton[10:35pm]/home/ports/net/nttcp-111#  cat /proc/curproc/map
0x11fdc000 0x11ffc000 1 0 0xfffffe0005f33550 rwx 1 0 0x2180 NCOW NNC default
0x120000000 0x120012000 9 10 0xfffffe0005b61340 r-x 2 1 0x0 COW NC vnode
0x120020000 0x120022000 1 0 0xfffffe000602bd90 rw- 1 0 0x2180 COW NNC vnode
0x120022000 0x120026000 2 0 0xfffffe0005f24210 rw- 2 0 0x2180 NCOW NNC default
0x120026000 0x120038000 2 0 0xfffffe0005f24210 rwx 2 0 0x2180 NCOW NNC default
0x160020000 0x160022000 1 0 0xfffffe0005c38420 rw- 1 0 0x2180 NCOW NNC default

I would guess 0x160021fff and growing down.

> 4) Where is the code that I should have read instead of bothering you?  The
>    rtld-elf code mentions the expectation that the "SVR4 ABI specification,
>    Intel 386 Processor Supplement" is adhered to, but I couldn't find
>    anything more specific.

Another useful tool for investigating this sort of thing is objdump.

peter@overcee[10:44pm]~src/sys-119> objdump --all-headers /bin/ls | more
[..]
start address 0x0804807c

Program Header:
    LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
         filesz 0x000282e0 memsz 0x000282e0 flags r-x
    LOAD off    0x000282e0 vaddr 0x080712e0 paddr 0x080712e0 align 2**12
         filesz 0x000012c4 memsz 0x0000a2b0 flags rw-

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .init         00000006  08048074  08048074  00000074  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .text         00024e10  0804807c  0804807c  0000007c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .fini         00000006  0806ce8c  0806ce8c  00024e8c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  3 .rodata       00003440  0806cea0  0806cea0  00024ea0  2**5
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .data         000012b4  080712e0  080712e0  000282e0  2**5
                  CONTENTS, ALLOC, LOAD, DATA
[...]

The program header is basically all that the exec handler looks at.  It's
the equivalent of the old text/data/bss counts in a.out.  In this case, it
means:

File offset 0 gets mmapped to 0x08048000, file length 0x000282e0 == mapping
length, read-only (ie: ELF metadata, text and rodata)
File offset 0x000282e0 gets mapped to 0x080712e0, the mapping is 0x0000a2b0
bytes long, but only the first 0x000012c4 bytes come from the file. The
gap must be zeroed.  This is the data (from the file) and bss (zeroed).

The section table is not used at run time.  It contains detail about what
is actually in the load section.

People often see the number of sections and compare that to the 3 in a.out
and have a heart attack.  There's sometimes 30 to 50 sections.  However,
the key is that only the program header is used at runtime and that
lives entirely in the first page of the file and only has two entries.

That's also ELF's big problem.  That hybrid data+bss section is a real pain
in the behind to get right, as there is one page that has got data from
the file and the rest is zeroed. You have to explicitly zero it otherwise
it gets metadata from the mmap of the file.  This is a real pain since it
causes an out-of-order read when execing as the demand loading causes execve
to pause in kernel mode while the page is pulled in.

On the plus side, with ELF you can specifically nominate your segment load
addresses and entry points.  If you want your .text to start at 0x6000, 
there is nothing at all stopping you, and the kernel will quite happily exec
it and everything will work.  You just tell ld and it arranges it.

> Thanks,
> Jason

Cheers,
-Peter
--
Peter Wemm - peter@FreeBSD.org; peter@yahoo-inc.com; peter@netplex.com.au



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?19990703145507.A4BD564>