#12438: Implement brk and sbrk
----------------------------+----------------------------
Reporter: simonsouth | Owner: nobody
Type: enhancement | Status: closed
Priority: normal | Milestone: Unscheduled
Component: System/POSIX | Version: R1/Development
Resolution: fixed | Keywords:
Blocked By: | Blocking:
Has a Patch: 0 | Platform: All
----------------------------+----------------------------
Comment (by korli):
I'm proposing this patch for review. Feedback welcome.
To help the actual sbrk() implementation, we try to free the space after
the program segments. For this to happen:
* the runtime_loader now loads the program first segment with its own
segment as a base address: this avoids the situation when the program is
loaded at a location before the runtime loader.
* the runtime loader now loads dependencies at a farer location (1GB on 32
bits), this avoids having libroot.so loaded near the program.
* the heap area isn't created on init any more: sbrk is first used to
provide the first allocations (until 64 pages), then only the heap area is
created: this avoids having an heap area to be created when the program
doesn't actually use malloc() (libgcc, libroot might still do though).
* tested on x86 and x86_64, sbrk() allocated 640M successfully.
{{{
diff --git a/src/system/libroot/posix/malloc/arch-specific.cpp
b/src/system/libroot/posix/malloc/arch-specific.cpp
index 4167f04..2831213 100644
--- a/src/system/libroot/posix/malloc/arch-specific.cpp
+++ b/src/system/libroot/posix/malloc/arch-specific.cpp
@@ -65,6 +65,7 @@ static void *sHeapBase;
static addr_t sFreeHeapBase;
static size_t sFreeHeapSize, sHeapAreaSize;
static free_chunk *sFreeChunks;
+static size_t sSbrkFreeSize;
static void
@@ -72,7 +73,7 @@ init_after_fork(void)
{
// find the heap area
sHeapArea = area_for((void*)sFreeHeapBase);
- if (sHeapArea < 0) {
+ if (sHeapArea < 0 && sSbrkFreeSize == 0) {
// Where is it gone?
debug_printf("hoard: init_after_fork(): thread %" B_PRId32
", Heap "
"area not found! Base address: %p\n",
find_thread(NULL),
@@ -96,17 +97,10 @@ __init_heap(void)
if (status != B_OK)
sHeapBase = NULL;
- uint32 protection = B_READ_AREA | B_WRITE_AREA;
- if (__gABIVersion < B_HAIKU_ABI_GCC_2_HAIKU)
- protection |= B_EXECUTE_AREA;
- sHeapArea = create_area("heap", (void **)&sHeapBase,
- status == B_OK ? B_EXACT_ADDRESS :
B_RANDOMIZED_BASE_ADDRESS,
- kInitialHeapSize, B_NO_LOCK, protection);
- if (sHeapArea < B_OK)
- return sHeapArea;
-
- sFreeHeapBase = (addr_t)sHeapBase;
- sHeapAreaSize = kInitialHeapSize;
+ sSbrkFreeSize = 64 * B_PAGE_SIZE;
+ sHeapArea = B_NO_INIT;
+ sFreeHeapBase = 0;
+ sHeapAreaSize = 0;
hoardLockInit(sHeapLock, "heap");
@@ -157,6 +151,16 @@ hoardSbrk(long size)
assert(size > 0);
CTRACE(("sbrk: size = %ld\n", size));
+ if (sSbrkFreeSize > 0 && size > 0) {
+ if ((size_t)size < sSbrkFreeSize) {
+ sSbrkFreeSize -= min_c((size_t)size,
sSbrkFreeSize);
+ void* ptr = sbrk(size);
+ if (ptr != (void*)-1)
+ return ptr;
+ }
+ sSbrkFreeSize = 0;
+ }
+
// align size request
size = (size + hoardHeap::ALIGNMENT - 1) & ~(hoardHeap::ALIGNMENT
- 1);
@@ -167,6 +171,19 @@ hoardSbrk(long size)
hoardLock(sHeapLock);
+ if (sFreeHeapBase == 0) {
+ sHeapArea = create_area("heap", (void **)&sHeapBase,
+ sHeapBase != NULL ? B_EXACT_ADDRESS :
B_RANDOMIZED_BASE_ADDRESS,
+ kInitialHeapSize, B_NO_LOCK, protection);
+ if (sHeapArea < B_OK) {
+ hoardUnlock(sHeapLock);
+ return NULL;
+ }
+
+ sFreeHeapBase = (addr_t)sHeapBase;
+ sHeapAreaSize = kInitialHeapSize;
+ }
+
// find chunk in free list
free_chunk *chunk = sFreeChunks, *last = NULL;
for (; chunk != NULL; chunk = chunk->next) {
diff --git a/src/system/runtime_loader/elf_load_image.cpp
b/src/system/runtime_loader/elf_load_image.cpp
index c6bcbbf..3f67675 100644
--- a/src/system/runtime_loader/elf_load_image.cpp
+++ b/src/system/runtime_loader/elf_load_image.cpp
@@ -527,7 +527,8 @@ load_image(char const* name, image_type type, const
char* rpath,
goto err2;
}
- status = map_image(fd, path, image, eheader.e_type == ET_EXEC);
+ status = map_image(fd, path, image, eheader.e_type == ET_EXEC,
+ type == B_APP_IMAGE);
if (status < B_OK) {
FATAL("%s: Could not map image: %s\n", image->path,
strerror(status));
status = B_ERROR;
diff --git a/src/system/runtime_loader/images.cpp
b/src/system/runtime_loader/images.cpp
index f2678a3..a291ffd 100644
--- a/src/system/runtime_loader/images.cpp
+++ b/src/system/runtime_loader/images.cpp
@@ -33,9 +33,11 @@
// page segment alignment.
# define RLD_PROGRAM_BASE 0x600000
# define MAX_PAGE_SIZE 0x200000
+# define RLD_NON_PROGRAM_BASE 0x100000000
#else
# define RLD_PROGRAM_BASE 0x200000
# define MAX_PAGE_SIZE B_PAGE_SIZE
+# define RLD_NON_PROGRAM_BASE 0x40000000
#endif
@@ -170,13 +172,20 @@ topological_sort(image_t* image, uint32 slot,
image_t** initList,
*/
static void
get_image_region_load_address(image_t* image, uint32 index, long
lastDelta,
- bool fixed, addr_t& loadAddress, uint32& addressSpecifier)
+ bool fixed, bool executable, addr_t& loadAddress, uint32&
addressSpecifier)
{
if (!fixed) {
// relocatable image... we can afford to place wherever
if (index == 0) {
// but only the first segment gets a free ride
- loadAddress = RLD_PROGRAM_BASE;
+ if (!executable)
+ // push libs farer in the address space
+ loadAddress = RLD_NON_PROGRAM_BASE;
+ else {
+ // check the provided address against the
program base
+ if (loadAddress < RLD_PROGRAM_BASE)
+ loadAddress = RLD_PROGRAM_BASE;
+ }
addressSpecifier = B_RANDOMIZED_BASE_ADDRESS;
} else {
loadAddress = image->regions[index].vmstart +
lastDelta;
@@ -287,7 +296,7 @@ put_image(image_t* image)
status_t
-map_image(int fd, char const* path, image_t* image, bool fixed)
+map_image(int fd, char const* path, image_t* image, bool fixed, bool
executable)
{
// cut the file name from the path as base name for the created
areas
const char* baseName = strrchr(path, '/');
@@ -304,6 +313,14 @@ map_image(int fd, char const* path, image_t* image,
bool fixed)
size_t length = 0;
uint32 addressSpecifier = B_RANDOMIZED_ANY_ADDRESS;
+ // find out our end of segment to be used as a base
+ area_id ourArea = _kern_area_for((void*)map_image);
+ if (ourArea > B_OK) {
+ area_info ourAreaInfo;
+ if (_kern_get_area_info(ourArea, &ourAreaInfo) == B_OK)
+ loadAddress = (addr_t)ourAreaInfo.address +
ourAreaInfo.size;
+ }
+
for (uint32 i = 0; i < image->num_regions; i++) {
// for BeOS compatibility: if we load an old BeOS
executable, we
// have to relocate it, if possible - we recognize it
because the
@@ -314,7 +331,7 @@ map_image(int fd, char const* path, image_t* image,
bool fixed)
uint32 regionAddressSpecifier;
get_image_region_load_address(image, i,
i > 0 ? loadAddress - image->regions[i -
1].vmstart : 0,
- fixed, loadAddress, regionAddressSpecifier);
+ fixed, executable, loadAddress,
regionAddressSpecifier);
if (i == 0) {
reservedAddress = loadAddress;
addressSpecifier = regionAddressSpecifier;
@@ -346,8 +363,8 @@ map_image(int fd, char const* path, image_t* image,
bool fixed)
baseName, i, (image->regions[i].flags & RFLAG_RW)
? "rw" : "ro");
get_image_region_load_address(image, i,
- i > 0 ? image->regions[i - 1].delta : 0, fixed,
loadAddress,
- addressSpecifier);
+ i > 0 ? image->regions[i - 1].delta : 0, fixed,
executable,
+ loadAddress, addressSpecifier);
// If the image position is arbitrary, we must let it
point to the start
// of the reserved address range.
diff --git a/src/system/runtime_loader/images.h
b/src/system/runtime_loader/images.h
index a929040..fa47f0c 100644
--- a/src/system/runtime_loader/images.h
+++ b/src/system/runtime_loader/images.h
@@ -50,7 +50,8 @@ void delete_image_struct(image_t* image);
void delete_image(image_t* image);
void put_image(image_t* image);
-status_t map_image(int fd, char const* path, image_t* image, bool
fixed);
+status_t map_image(int fd, char const* path, image_t* image, bool
fixed,
+ bool executable);
void unmap_image(image_t* image);
void remap_images();
}}}
--
Ticket URL: <https://dev.haiku-os.org/ticket/12438#comment:12>
Haiku <https://dev.haiku-os.org>
Haiku - the operating system.