Index: kernel/generic/include/mm/as.h
===================================================================
--- kernel/generic/include/mm/as.h	(revision ae6f303748db0f9a242fb1a15affe2c3ee62e621)
+++ kernel/generic/include/mm/as.h	(revision 0b378820b4861f67ea1335ef6260a5c98a59c64c)
@@ -313,4 +313,5 @@
 extern sysarg_t sys_as_area_change_flags(uintptr_t, unsigned int);
 extern sysarg_t sys_as_area_destroy(uintptr_t);
+extern sysarg_t sys_as_get_unmapped_area(uintptr_t, size_t);
 
 /* Introspection functions. */
Index: kernel/generic/include/syscall/syscall.h
===================================================================
--- kernel/generic/include/syscall/syscall.h	(revision ae6f303748db0f9a242fb1a15affe2c3ee62e621)
+++ kernel/generic/include/syscall/syscall.h	(revision 0b378820b4861f67ea1335ef6260a5c98a59c64c)
@@ -59,4 +59,5 @@
 	SYS_AS_AREA_CHANGE_FLAGS,
 	SYS_AS_AREA_DESTROY,
+	SYS_AS_GET_UNMAPPED_AREA,
 	
 	SYS_IPC_CALL_SYNC_FAST,
Index: kernel/generic/src/mm/as.c
===================================================================
--- kernel/generic/src/mm/as.c	(revision ae6f303748db0f9a242fb1a15affe2c3ee62e621)
+++ kernel/generic/src/mm/as.c	(revision 0b378820b4861f67ea1335ef6260a5c98a59c64c)
@@ -71,4 +71,5 @@
 #include <memstr.h>
 #include <macros.h>
+#include <bitops.h>
 #include <arch.h>
 #include <errno.h>
@@ -288,15 +289,16 @@
 /** Check area conflicts with other areas.
  *
- * @param as         Address space.
- * @param va         Starting virtual address of the area being tested.
- * @param size       Size of the area being tested.
- * @param avoid_area Do not touch this area.
+ * @param as    Address space.
+ * @param addr  Starting virtual address of the area being tested.
+ * @param count Number of pages in the area being tested.
+ * @param avoid Do not touch this area.
  *
  * @return True if there is no conflict, false otherwise.
  *
  */
-NO_TRACE static bool check_area_conflicts(as_t *as, uintptr_t va, size_t size,
-    as_area_t *avoid_area)
-{
+NO_TRACE static bool check_area_conflicts(as_t *as, uintptr_t addr,
+    size_t count, as_area_t *avoid)
+{
+	ASSERT((addr % PAGE_SIZE) == 0);
 	ASSERT(mutex_locked(&as->lock));
 	
@@ -304,5 +306,5 @@
 	 * We don't want any area to have conflicts with NULL page.
 	 */
-	if (overlaps(va, size, (uintptr_t) NULL, PAGE_SIZE))
+	if (overlaps(addr, count << PAGE_WIDTH, (uintptr_t) NULL, PAGE_SIZE))
 		return false;
 	
@@ -316,7 +318,7 @@
 	btree_node_t *leaf;
 	as_area_t *area =
-	    (as_area_t *) btree_search(&as->as_area_btree, va, &leaf);
+	    (as_area_t *) btree_search(&as->as_area_btree, addr, &leaf);
 	if (area) {
-		if (area != avoid_area)
+		if (area != avoid)
 			return false;
 	}
@@ -328,12 +330,15 @@
 		area = (as_area_t *) node->value[node->keys - 1];
 		
-		mutex_lock(&area->lock);
-		
-		if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {
+		if (area != avoid) {
+			mutex_lock(&area->lock);
+			
+			if (overlaps(addr, count << PAGE_WIDTH,
+			    area->base, area->pages << PAGE_WIDTH)) {
+				mutex_unlock(&area->lock);
+				return false;
+			}
+			
 			mutex_unlock(&area->lock);
-			return false;
-		}
-		
-		mutex_unlock(&area->lock);
+		}
 	}
 	
@@ -342,12 +347,15 @@
 		area = (as_area_t *) node->value[0];
 		
-		mutex_lock(&area->lock);
-		
-		if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {
+		if (area != avoid) {
+			mutex_lock(&area->lock);
+			
+			if (overlaps(addr, count << PAGE_WIDTH,
+			    area->base, area->pages << PAGE_WIDTH)) {
+				mutex_unlock(&area->lock);
+				return false;
+			}
+			
 			mutex_unlock(&area->lock);
-			return false;
-		}
-		
-		mutex_unlock(&area->lock);
+		}
 	}
 	
@@ -357,10 +365,11 @@
 		area = (as_area_t *) leaf->value[i];
 		
-		if (area == avoid_area)
+		if (area == avoid)
 			continue;
 		
 		mutex_lock(&area->lock);
 		
-		if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {
+		if (overlaps(addr, count << PAGE_WIDTH,
+		    area->base, area->pages << PAGE_WIDTH)) {
 			mutex_unlock(&area->lock);
 			return false;
@@ -375,5 +384,5 @@
 	 */
 	if (!KERNEL_ADDRESS_SPACE_SHADOWED) {
-		return !overlaps(va, size,
+		return !overlaps(addr, count << PAGE_WIDTH,
 		    KERNEL_ADDRESS_SPACE_START,
 		    KERNEL_ADDRESS_SPACE_END - KERNEL_ADDRESS_SPACE_START);
@@ -402,9 +411,11 @@
     mem_backend_data_t *backend_data)
 {
-	if (base % PAGE_SIZE)
+	if ((base % PAGE_SIZE) != 0)
 		return NULL;
 	
-	if (!size)
+	if (size == 0)
 		return NULL;
+	
+	size_t pages = SIZE2FRAMES(size);
 	
 	/* Writeable executable areas are not supported. */
@@ -414,5 +425,5 @@
 	mutex_lock(&as->lock);
 	
-	if (!check_area_conflicts(as, base, size, NULL)) {
+	if (!check_area_conflicts(as, base, pages, NULL)) {
 		mutex_unlock(&as->lock);
 		return NULL;
@@ -426,5 +437,5 @@
 	area->flags = flags;
 	area->attributes = attrs;
-	area->pages = SIZE2FRAMES(size);
+	area->pages = pages;
 	area->resident = 0;
 	area->base = base;
@@ -480,5 +491,6 @@
 		mutex_lock(&area->lock);
 		
-		if ((area->base <= va) && (va < area->base + area->pages * PAGE_SIZE))
+		if ((area->base <= va) &&
+		    (va < area->base + (area->pages << PAGE_WIDTH)))
 			return area;
 		
@@ -496,5 +508,5 @@
 		mutex_lock(&area->lock);
 		
-		if (va < area->base + area->pages * PAGE_SIZE)
+		if (va < area->base + (area->pages << PAGE_WIDTH))
 			return area;
 		
@@ -561,5 +573,5 @@
 	
 	if (pages < area->pages) {
-		uintptr_t start_free = area->base + pages * PAGE_SIZE;
+		uintptr_t start_free = area->base + (pages << PAGE_WIDTH);
 		
 		/*
@@ -574,5 +586,5 @@
 		 */
 		ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES, as->asid,
-		    area->base + pages * PAGE_SIZE, area->pages - pages);
+		    area->base + (pages << PAGE_WIDTH), area->pages - pages);
 		
 		/*
@@ -597,8 +609,8 @@
 				size_t i = 0;
 				
-				if (overlaps(ptr, size * PAGE_SIZE, area->base,
-				    pages * PAGE_SIZE)) {
+				if (overlaps(ptr, size << PAGE_WIDTH, area->base,
+				    pages << PAGE_WIDTH)) {
 					
-					if (ptr + size * PAGE_SIZE <= start_free) {
+					if (ptr + (size << PAGE_WIDTH) <= start_free) {
 						/*
 						 * The whole interval fits
@@ -632,5 +644,5 @@
 				for (; i < size; i++) {
 					pte_t *pte = page_mapping_find(as, ptr +
-					    i * PAGE_SIZE);
+					    (i << PAGE_WIDTH));
 					
 					ASSERT(pte);
@@ -641,10 +653,10 @@
 					    (area->backend->frame_free)) {
 						area->backend->frame_free(area,
-						    ptr + i * PAGE_SIZE,
+						    ptr + (i << PAGE_WIDTH),
 						    PTE_GET_FRAME(pte));
 					}
 					
 					page_mapping_remove(as, ptr +
-					    i * PAGE_SIZE);
+					    (i << PAGE_WIDTH));
 				}
 			}
@@ -655,5 +667,5 @@
 		 */
 		
-		tlb_invalidate_pages(as->asid, area->base + pages * PAGE_SIZE,
+		tlb_invalidate_pages(as->asid, area->base + (pages << PAGE_WIDTH),
 		    area->pages - pages);
 		
@@ -662,5 +674,5 @@
 		 */
 		as_invalidate_translation_cache(as, area->base +
-		    pages * PAGE_SIZE, area->pages - pages);
+		    (pages << PAGE_WIDTH), area->pages - pages);
 		tlb_shootdown_finalize(ipl);
 		
@@ -671,6 +683,5 @@
 		 * Check for overlaps with other address space areas.
 		 */
-		if (!check_area_conflicts(as, address, pages * PAGE_SIZE,
-		    area)) {
+		if (!check_area_conflicts(as, address, pages, area)) {
 			mutex_unlock(&area->lock);
 			mutex_unlock(&as->lock);
@@ -771,5 +782,6 @@
 			
 			for (size = 0; size < (size_t) node->value[i]; size++) {
-				pte_t *pte = page_mapping_find(as, ptr + size * PAGE_SIZE);
+				pte_t *pte =
+				    page_mapping_find(as, ptr + (size << PAGE_WIDTH));
 				
 				ASSERT(pte);
@@ -780,8 +792,8 @@
 				    (area->backend->frame_free)) {
 					area->backend->frame_free(area,
-					    ptr + size * PAGE_SIZE, PTE_GET_FRAME(pte));
+					    ptr + (size << PAGE_WIDTH), PTE_GET_FRAME(pte));
 				}
 				
-				page_mapping_remove(as, ptr + size * PAGE_SIZE);
+				page_mapping_remove(as, ptr + (size << PAGE_WIDTH));
 			}
 		}
@@ -870,5 +882,5 @@
 	}
 	
-	size_t src_size = src_area->pages * PAGE_SIZE;
+	size_t src_size = src_area->pages << PAGE_WIDTH;
 	unsigned int src_flags = src_area->flags;
 	mem_backend_t *src_backend = src_area->backend;
@@ -1076,5 +1088,6 @@
 			
 			for (size = 0; size < (size_t) node->value[i]; size++) {
-				pte_t *pte = page_mapping_find(as, ptr + size * PAGE_SIZE);
+				pte_t *pte =
+				    page_mapping_find(as, ptr + (size << PAGE_WIDTH));
 				
 				ASSERT(pte);
@@ -1085,5 +1098,5 @@
 				
 				/* Remove old mapping */
-				page_mapping_remove(as, ptr + size * PAGE_SIZE);
+				page_mapping_remove(as, ptr + (size << PAGE_WIDTH));
 			}
 		}
@@ -1131,5 +1144,5 @@
 				
 				/* Insert the new mapping */
-				page_mapping_insert(as, ptr + size * PAGE_SIZE,
+				page_mapping_insert(as, ptr + (size << PAGE_WIDTH),
 				    old_frame[frame_idx++], page_flags);
 				
@@ -1453,5 +1466,5 @@
 	
 	if (src_area) {
-		size = src_area->pages * PAGE_SIZE;
+		size = src_area->pages << PAGE_WIDTH;
 		mutex_unlock(&src_area->lock);
 	} else
@@ -1508,14 +1521,14 @@
 		if (page >= right_pg) {
 			/* Do nothing. */
-		} else if (overlaps(page, count * PAGE_SIZE, left_pg,
-		    left_cnt * PAGE_SIZE)) {
+		} else if (overlaps(page, count << PAGE_WIDTH, left_pg,
+		    left_cnt << PAGE_WIDTH)) {
 			/* The interval intersects with the left interval. */
 			return false;
-		} else if (overlaps(page, count * PAGE_SIZE, right_pg,
-		    right_cnt * PAGE_SIZE)) {
+		} else if (overlaps(page, count << PAGE_WIDTH, right_pg,
+		    right_cnt << PAGE_WIDTH)) {
 			/* The interval intersects with the right interval. */
 			return false;
-		} else if ((page == left_pg + left_cnt * PAGE_SIZE) &&
-		    (page + count * PAGE_SIZE == right_pg)) {
+		} else if ((page == left_pg + (left_cnt << PAGE_WIDTH)) &&
+		    (page + (count << PAGE_WIDTH) == right_pg)) {
 			/*
 			 * The interval can be added by merging the two already
@@ -1525,5 +1538,5 @@
 			btree_remove(&area->used_space, right_pg, leaf);
 			goto success;
-		} else if (page == left_pg + left_cnt * PAGE_SIZE) {
+		} else if (page == left_pg + (left_cnt << PAGE_WIDTH)) {
 			/*
 			 * The interval can be added by simply growing the left
@@ -1532,5 +1545,5 @@
 			node->value[node->keys - 1] += count;
 			goto success;
-		} else if (page + count * PAGE_SIZE == right_pg) {
+		} else if (page + (count << PAGE_WIDTH) == right_pg) {
 			/*
 			 * The interval can be addded by simply moving base of
@@ -1559,9 +1572,9 @@
 		 */
 		
-		if (overlaps(page, count * PAGE_SIZE, right_pg,
-		    right_cnt * PAGE_SIZE)) {
+		if (overlaps(page, count << PAGE_WIDTH, right_pg,
+		    right_cnt << PAGE_WIDTH)) {
 			/* The interval intersects with the right interval. */
 			return false;
-		} else if (page + count * PAGE_SIZE == right_pg) {
+		} else if (page + (count << PAGE_WIDTH) == right_pg) {
 			/*
 			 * The interval can be added by moving the base of the
@@ -1598,14 +1611,14 @@
 		if (page < left_pg) {
 			/* Do nothing. */
-		} else if (overlaps(page, count * PAGE_SIZE, left_pg,
-		    left_cnt * PAGE_SIZE)) {
+		} else if (overlaps(page, count << PAGE_WIDTH, left_pg,
+		    left_cnt << PAGE_WIDTH)) {
 			/* The interval intersects with the left interval. */
 			return false;
-		} else if (overlaps(page, count * PAGE_SIZE, right_pg,
-		    right_cnt * PAGE_SIZE)) {
+		} else if (overlaps(page, count << PAGE_WIDTH, right_pg,
+		    right_cnt << PAGE_WIDTH)) {
 			/* The interval intersects with the right interval. */
 			return false;
-		} else if ((page == left_pg + left_cnt * PAGE_SIZE) &&
-		    (page + count * PAGE_SIZE == right_pg)) {
+		} else if ((page == left_pg + (left_cnt << PAGE_WIDTH)) &&
+		    (page + (count << PAGE_WIDTH) == right_pg)) {
 			/*
 			 * The interval can be added by merging the two already
@@ -1615,5 +1628,5 @@
 			btree_remove(&area->used_space, right_pg, node);
 			goto success;
-		} else if (page == left_pg + left_cnt * PAGE_SIZE) {
+		} else if (page == left_pg + (left_cnt << PAGE_WIDTH)) {
 			/*
 			 * The interval can be added by simply growing the left
@@ -1622,5 +1635,5 @@
 			leaf->value[leaf->keys - 1] += count;
 			goto success;
-		} else if (page + count * PAGE_SIZE == right_pg) {
+		} else if (page + (count << PAGE_WIDTH) == right_pg) {
 			/*
 			 * The interval can be addded by simply moving base of
@@ -1649,9 +1662,9 @@
 		 */
 		
-		if (overlaps(page, count * PAGE_SIZE, left_pg,
-		    left_cnt * PAGE_SIZE)) {
+		if (overlaps(page, count << PAGE_WIDTH, left_pg,
+		    left_cnt << PAGE_WIDTH)) {
 			/* The interval intersects with the left interval. */
 			return false;
-		} else if (left_pg + left_cnt * PAGE_SIZE == page) {
+		} else if (left_pg + (left_cnt << PAGE_WIDTH) == page) {
 			/*
 			 * The interval can be added by growing the left
@@ -1688,6 +1701,6 @@
 			 */
 			
-			if (overlaps(page, count * PAGE_SIZE, left_pg,
-			    left_cnt * PAGE_SIZE)) {
+			if (overlaps(page, count << PAGE_WIDTH, left_pg,
+			    left_cnt << PAGE_WIDTH)) {
 				/*
 				 * The interval intersects with the left
@@ -1695,6 +1708,6 @@
 				 */
 				return false;
-			} else if (overlaps(page, count * PAGE_SIZE, right_pg,
-			    right_cnt * PAGE_SIZE)) {
+			} else if (overlaps(page, count << PAGE_WIDTH, right_pg,
+			    right_cnt << PAGE_WIDTH)) {
 				/*
 				 * The interval intersects with the right
@@ -1702,6 +1715,6 @@
 				 */
 				return false;
-			} else if ((page == left_pg + left_cnt * PAGE_SIZE) &&
-			    (page + count * PAGE_SIZE == right_pg)) {
+			} else if ((page == left_pg + (left_cnt << PAGE_WIDTH)) &&
+			    (page + (count << PAGE_WIDTH) == right_pg)) {
 				/*
 				 * The interval can be added by merging the two
@@ -1711,5 +1724,5 @@
 				btree_remove(&area->used_space, right_pg, leaf);
 				goto success;
-			} else if (page == left_pg + left_cnt * PAGE_SIZE) {
+			} else if (page == left_pg + (left_cnt << PAGE_WIDTH)) {
 				/*
 				 * The interval can be added by simply growing
@@ -1718,5 +1731,5 @@
 				leaf->value[i - 1] += count;
 				goto success;
-			} else if (page + count * PAGE_SIZE == right_pg) {
+			} else if (page + (count << PAGE_WIDTH) == right_pg) {
 				/*
 				 * The interval can be addded by simply moving
@@ -1784,5 +1797,5 @@
 			for (i = 0; i < leaf->keys; i++) {
 				if (leaf->key[i] == page) {
-					leaf->key[i] += count * PAGE_SIZE;
+					leaf->key[i] += count << PAGE_WIDTH;
 					leaf->value[i] -= count;
 					goto success;
@@ -1799,8 +1812,8 @@
 		size_t left_cnt = (size_t) node->value[node->keys - 1];
 		
-		if (overlaps(left_pg, left_cnt * PAGE_SIZE, page,
-		    count * PAGE_SIZE)) {
-			if (page + count * PAGE_SIZE ==
-			    left_pg + left_cnt * PAGE_SIZE) {
+		if (overlaps(left_pg, left_cnt << PAGE_WIDTH, page,
+		    count << PAGE_WIDTH)) {
+			if (page + (count << PAGE_WIDTH) ==
+			    left_pg + (left_cnt << PAGE_WIDTH)) {
 				/*
 				 * The interval is contained in the rightmost
@@ -1811,6 +1824,6 @@
 				node->value[node->keys - 1] -= count;
 				goto success;
-			} else if (page + count * PAGE_SIZE <
-			    left_pg + left_cnt*PAGE_SIZE) {
+			} else if (page + (count << PAGE_WIDTH) <
+			    left_pg + (left_cnt << PAGE_WIDTH)) {
 				/*
 				 * The interval is contained in the rightmost
@@ -1820,9 +1833,9 @@
 				 * new interval.
 				 */
-				size_t new_cnt = ((left_pg + left_cnt * PAGE_SIZE) -
-				    (page + count*PAGE_SIZE)) >> PAGE_WIDTH;
+				size_t new_cnt = ((left_pg + (left_cnt << PAGE_WIDTH)) -
+				    (page + (count << PAGE_WIDTH))) >> PAGE_WIDTH;
 				node->value[node->keys - 1] -= count + new_cnt;
 				btree_insert(&area->used_space, page +
-				    count * PAGE_SIZE, (void *) new_cnt, leaf);
+				    (count << PAGE_WIDTH), (void *) new_cnt, leaf);
 				goto success;
 			}
@@ -1837,8 +1850,8 @@
 		size_t left_cnt = (size_t) leaf->value[leaf->keys - 1];
 		
-		if (overlaps(left_pg, left_cnt * PAGE_SIZE, page,
-		    count * PAGE_SIZE)) {
-			if (page + count * PAGE_SIZE ==
-			    left_pg + left_cnt * PAGE_SIZE) {
+		if (overlaps(left_pg, left_cnt << PAGE_WIDTH, page,
+		    count << PAGE_WIDTH)) {
+			if (page + (count << PAGE_WIDTH) ==
+			    left_pg + (left_cnt << PAGE_WIDTH)) {
 				/*
 				 * The interval is contained in the rightmost
@@ -1848,6 +1861,6 @@
 				leaf->value[leaf->keys - 1] -= count;
 				goto success;
-			} else if (page + count * PAGE_SIZE < left_pg +
-			    left_cnt * PAGE_SIZE) {
+			} else if (page + (count << PAGE_WIDTH) < left_pg +
+			    (left_cnt << PAGE_WIDTH)) {
 				/*
 				 * The interval is contained in the rightmost
@@ -1857,9 +1870,9 @@
 				 * interval.
 				 */
-				size_t new_cnt = ((left_pg + left_cnt * PAGE_SIZE) -
-				    (page + count * PAGE_SIZE)) >> PAGE_WIDTH;
+				size_t new_cnt = ((left_pg + (left_cnt << PAGE_WIDTH)) -
+				    (page + (count << PAGE_WIDTH))) >> PAGE_WIDTH;
 				leaf->value[leaf->keys - 1] -= count + new_cnt;
 				btree_insert(&area->used_space, page +
-				    count * PAGE_SIZE, (void *) new_cnt, leaf);
+				    (count << PAGE_WIDTH), (void *) new_cnt, leaf);
 				goto success;
 			}
@@ -1883,8 +1896,8 @@
 			 * to (i - 1) and i.
 			 */
-			if (overlaps(left_pg, left_cnt * PAGE_SIZE, page,
-			    count * PAGE_SIZE)) {
-				if (page + count * PAGE_SIZE ==
-				    left_pg + left_cnt*PAGE_SIZE) {
+			if (overlaps(left_pg, left_cnt << PAGE_WIDTH, page,
+			    count << PAGE_WIDTH)) {
+				if (page + (count << PAGE_WIDTH) ==
+				    left_pg + (left_cnt << PAGE_WIDTH)) {
 					/*
 					 * The interval is contained in the
@@ -1895,6 +1908,6 @@
 					leaf->value[i - 1] -= count;
 					goto success;
-				} else if (page + count * PAGE_SIZE <
-				    left_pg + left_cnt * PAGE_SIZE) {
+				} else if (page + (count << PAGE_WIDTH) <
+				    left_pg + (left_cnt << PAGE_WIDTH)) {
 					/*
 					 * The interval is contained in the
@@ -1905,10 +1918,10 @@
 					 */
 					size_t new_cnt = ((left_pg +
-					    left_cnt * PAGE_SIZE) -
-					    (page + count * PAGE_SIZE)) >>
+					    (left_cnt << PAGE_WIDTH)) -
+					    (page + (count << PAGE_WIDTH))) >>
 					    PAGE_WIDTH;
 					leaf->value[i - 1] -= count + new_cnt;
 					btree_insert(&area->used_space, page +
-					    count * PAGE_SIZE, (void *) new_cnt,
+					    (count << PAGE_WIDTH), (void *) new_cnt,
 					    leaf);
 					goto success;
@@ -1961,4 +1974,70 @@
 }
 
+/** Return pointer to unmapped address space area
+ *
+ * @param base Lowest address bound.
+ * @param size Requested size of the allocation.
+ *
+ * @return Pointer to the beginning of unmapped address space area.
+ *
+ */
+sysarg_t sys_as_get_unmapped_area(uintptr_t base, size_t size)
+{
+	if (size == 0)
+		return 0;
+	
+	/*
+	 * Make sure we allocate from page-aligned
+	 * address. Check for possible overflow in
+	 * each step.
+	 */
+	
+	size_t pages = SIZE2FRAMES(size);
+	uintptr_t ret = 0;
+	
+	/*
+	 * Find the lowest unmapped address aligned on the sz
+	 * boundary, not smaller than base and of the required size.
+	 */
+	
+	mutex_lock(&AS->lock);
+	
+	/* First check the base address itself */
+	uintptr_t addr = ALIGN_UP(base, PAGE_SIZE);
+	if ((addr >= base) &&
+	    (check_area_conflicts(AS, addr, pages, NULL)))
+		ret = addr;
+	
+	/* Eventually check the addresses behind each area */
+	link_t *cur;
+	for (cur = AS->as_area_btree.leaf_head.next;
+	    (ret == 0) && (cur != &AS->as_area_btree.leaf_head);
+	    cur = cur->next) {
+		btree_node_t *node =
+		    list_get_instance(cur, btree_node_t, leaf_link);
+		
+		btree_key_t i;
+		for (i = 0; (ret == 0) && (i < node->keys); i++) {
+			as_area_t *area = (as_area_t *) node->value[i];
+			
+			mutex_lock(&area->lock);
+			
+			uintptr_t addr =
+			    ALIGN_UP(area->base + (area->pages << PAGE_WIDTH),
+			    PAGE_SIZE);
+			
+			if ((addr >= base) && (addr >= area->base) &&
+			    (check_area_conflicts(AS, addr, pages, area)))
+				ret = addr;
+			
+			mutex_unlock(&area->lock);
+		}
+	}
+	
+	mutex_unlock(&AS->lock);
+	
+	return (sysarg_t) ret;
+}
+
 /** Get list of adress space areas.
  *
@@ -2027,5 +2106,5 @@
 	mutex_lock(&as->lock);
 	
-	/* print out info about address space areas */
+	/* Print out info about address space areas */
 	link_t *cur;
 	for (cur = as->as_area_btree.leaf_head.next;
Index: kernel/generic/src/syscall/syscall.c
===================================================================
--- kernel/generic/src/syscall/syscall.c	(revision ae6f303748db0f9a242fb1a15affe2c3ee62e621)
+++ kernel/generic/src/syscall/syscall.c	(revision 0b378820b4861f67ea1335ef6260a5c98a59c64c)
@@ -143,4 +143,5 @@
 	(syshandler_t) sys_as_area_change_flags,
 	(syshandler_t) sys_as_area_destroy,
+	(syshandler_t) sys_as_get_unmapped_area,
 	
 	/* IPC related syscalls. */
Index: uspace/lib/c/generic/as.c
===================================================================
--- uspace/lib/c/generic/as.c	(revision ae6f303748db0f9a242fb1a15affe2c3ee62e621)
+++ uspace/lib/c/generic/as.c	(revision 0b378820b4861f67ea1335ef6260a5c98a59c64c)
@@ -40,7 +40,5 @@
 #include <bitops.h>
 #include <malloc.h>
-
-/** Last position allocated by as_get_mappable_page */
-static uintptr_t last_allocated = 0;
+#include "private/libc.h"
 
 /** Create address space area.
@@ -103,27 +101,15 @@
 }
 
-/** Return pointer to some unmapped area, where fits new as_area
+/** Return pointer to unmapped address space area
  *
  * @param size Requested size of the allocation.
  *
- * @return pointer to the beginning
+ * @return Pointer to the beginning of unmapped address space area.
  *
  */
 void *as_get_mappable_page(size_t size)
 {
-	if (size == 0)
-		return NULL;
-	
-	size_t sz = 1 << (fnzb(size - 1) + 1);
-	if (last_allocated == 0)
-		last_allocated = get_max_heap_addr();
-	
-	/*
-	 * Make sure we allocate from naturally aligned address.
-	 */
-	uintptr_t res = ALIGN_UP(last_allocated, sz);
-	last_allocated = res + ALIGN_UP(size, PAGE_SIZE);
-	
-	return ((void *) res);
+	return (void *) __SYSCALL2(SYS_AS_GET_UNMAPPED_AREA,
+	    (sysarg_t) __entry, (sysarg_t) size);
 }
 
Index: uspace/lib/c/generic/malloc.c
===================================================================
--- uspace/lib/c/generic/malloc.c	(revision ae6f303748db0f9a242fb1a15affe2c3ee62e621)
+++ uspace/lib/c/generic/malloc.c	(revision 0b378820b4861f67ea1335ef6260a5c98a59c64c)
@@ -47,33 +47,77 @@
 #include "private/malloc.h"
 
-/* Magic used in heap headers. */
-#define HEAP_BLOCK_HEAD_MAGIC  0xBEEF0101
-
-/* Magic used in heap footers. */
-#define HEAP_BLOCK_FOOT_MAGIC  0xBEEF0202
-
-/** Allocation alignment (this also covers the alignment of fields
-    in the heap header and footer) */
+/** Magic used in heap headers. */
+#define HEAP_BLOCK_HEAD_MAGIC  UINT32_C(0xBEEF0101)
+
+/** Magic used in heap footers. */
+#define HEAP_BLOCK_FOOT_MAGIC  UINT32_C(0xBEEF0202)
+
+/** Magic used in heap descriptor. */
+#define HEAP_AREA_MAGIC  UINT32_C(0xBEEFCAFE)
+
+/** Allocation alignment.
+ *
+ * This also covers the alignment of fields
+ * in the heap header and footer.
+ *
+ */
 #define BASE_ALIGN  16
 
-/**
- * Either 4 * 256M on 32-bit architecures or 16 * 256M on 64-bit architectures
- */
-#define MAX_HEAP_SIZE  (sizeof(uintptr_t) << 28)
-
-/**
- *
- */
-#define STRUCT_OVERHEAD  (sizeof(heap_block_head_t) + sizeof(heap_block_foot_t))
-
-/**
- * Calculate real size of a heap block (with header and footer)
+/** Overhead of each heap block. */
+#define STRUCT_OVERHEAD \
+	(sizeof(heap_block_head_t) + sizeof(heap_block_foot_t))
+
+/** Calculate real size of a heap block.
+ *
+ * Add header and footer size.
+ *
  */
 #define GROSS_SIZE(size)  ((size) + STRUCT_OVERHEAD)
 
-/**
- * Calculate net size of a heap block (without header and footer)
+/** Calculate net size of a heap block.
+ *
+ * Subtract header and footer size.
+ *
  */
 #define NET_SIZE(size)  ((size) - STRUCT_OVERHEAD)
+
+/** Get first block in heap area.
+ *
+ */
+#define AREA_FIRST_BLOCK(area) \
+	(ALIGN_UP(((uintptr_t) (area)) + sizeof(heap_area_t), BASE_ALIGN))
+
+/** Get footer in heap block.
+ *
+ */
+#define BLOCK_FOOT(head) \
+	((heap_block_foot_t *) \
+	    (((uintptr_t) head) + head->size - sizeof(heap_block_foot_t)))
+
+/** Heap area.
+ *
+ * The memory managed by the heap allocator is divided into
+ * multiple discontinuous heaps. Each heap is represented
+ * by a separate address space area which has this structure
+ * at its very beginning.
+ *
+ */
+typedef struct heap_area {
+	/** Start of the heap area (including this structure)
+	 *
+	 * Aligned on page boundary.
+	 *
+	 */
+	void *start;
+	
+	/** End of the heap area (aligned on page boundary) */
+	void *end;
+	
+	/** Next heap area */
+	struct heap_area *next;
+	
+	/** A magic value */
+	uint32_t magic;
+} heap_area_t;
 
 /** Header of a heap block
@@ -87,4 +131,7 @@
 	bool free;
 	
+	/** Heap area this block belongs to */
+	heap_area_t *area;
+	
 	/* A magic value to detect overwrite of heap header */
 	uint32_t magic;
@@ -102,25 +149,19 @@
 } heap_block_foot_t;
 
-/** Linker heap symbol */
-extern char _heap;
+/** First heap area */
+static heap_area_t *first_heap_area = NULL;
+
+/** Last heap area */
+static heap_area_t *last_heap_area = NULL;
+
+/** Next heap block to examine (next fit algorithm) */
+static heap_block_head_t *next = NULL;
 
 /** Futex for thread-safe heap manipulation */
 static futex_t malloc_futex = FUTEX_INITIALIZER;
 
-/** Address of heap start */
-static void *heap_start = 0;
-
-/** Address of heap end */
-static void *heap_end = 0;
-
-/** Maximum heap size */
-static size_t max_heap_size = (size_t) -1;
-
-/** Current number of pages of heap area */
-static size_t heap_pages = 0;
-
 /** Initialize a heap block
  *
- * Fills in the structures related to a heap block.
+ * Fill in the structures related to a heap block.
  * Should be called only inside the critical section.
  *
@@ -128,16 +169,18 @@
  * @param size Size of the block including the header and the footer.
  * @param free Indication of a free block.
- *
- */
-static void block_init(void *addr, size_t size, bool free)
+ * @param area Heap area the block belongs to.
+ *
+ */
+static void block_init(void *addr, size_t size, bool free, heap_area_t *area)
 {
 	/* Calculate the position of the header and the footer */
 	heap_block_head_t *head = (heap_block_head_t *) addr;
-	heap_block_foot_t *foot =
-	    (heap_block_foot_t *) (addr + size - sizeof(heap_block_foot_t));
 	
 	head->size = size;
 	head->free = free;
+	head->area = area;
 	head->magic = HEAP_BLOCK_HEAD_MAGIC;
+	
+	heap_block_foot_t *foot = BLOCK_FOOT(head);
 	
 	foot->size = size;
@@ -160,6 +203,5 @@
 	assert(head->magic == HEAP_BLOCK_HEAD_MAGIC);
 	
-	heap_block_foot_t *foot =
-	    (heap_block_foot_t *) (addr + head->size - sizeof(heap_block_foot_t));
+	heap_block_foot_t *foot = BLOCK_FOOT(head);
 	
 	assert(foot->magic == HEAP_BLOCK_FOOT_MAGIC);
@@ -167,49 +209,130 @@
 }
 
-/** Increase the heap area size
- *
- * Should be called only inside the critical section.
- *
- * @param size Number of bytes to grow the heap by.
- *
- */
-static bool grow_heap(size_t size)
+/** Check a heap area structure
+ *
+ * @param addr Address of the heap area.
+ *
+ */
+static void area_check(void *addr)
+{
+	heap_area_t *area = (heap_area_t *) addr;
+	
+	assert(area->magic == HEAP_AREA_MAGIC);
+	assert(area->start < area->end);
+	assert(((uintptr_t) area->start % PAGE_SIZE) == 0);
+	assert(((uintptr_t) area->end % PAGE_SIZE) == 0);
+}
+
+/** Create new heap area
+ *
+ * @param start Preffered starting address of the new area.
+ * @param size  Size of the area.
+ *
+ */
+static bool area_create(size_t size)
+{
+	void *start = as_get_mappable_page(size);
+	if (start == NULL)
+		return false;
+	
+	/* Align the heap area on page boundary */
+	void *astart = (void *) ALIGN_UP((uintptr_t) start, PAGE_SIZE);
+	size_t asize = ALIGN_UP(size, PAGE_SIZE);
+	
+	astart = as_area_create(astart, asize, AS_AREA_WRITE | AS_AREA_READ);
+	if (astart == (void *) -1)
+		return false;
+	
+	heap_area_t *area = (heap_area_t *) astart;
+	
+	area->start = astart;
+	area->end = (void *)
+	    ALIGN_DOWN((uintptr_t) astart + asize, BASE_ALIGN);
+	area->next = NULL;
+	area->magic = HEAP_AREA_MAGIC;
+	
+	void *block = (void *) AREA_FIRST_BLOCK(area);
+	size_t bsize = (size_t) (area->end - block);
+	
+	block_init(block, bsize, true, area);
+	
+	if (last_heap_area == NULL) {
+		first_heap_area = area;
+		last_heap_area = area;
+	} else {
+		last_heap_area->next = area;
+		last_heap_area = area;
+	}
+	
+	return true;
+}
+
+/** Try to enlarge a heap area
+ *
+ * @param area Heap area to grow.
+ * @param size Gross size of item to allocate (bytes).
+ *
+ */
+static bool area_grow(heap_area_t *area, size_t size)
 {
 	if (size == 0)
+		return true;
+	
+	area_check(area);
+	
+	size_t asize = ALIGN_UP((size_t) (area->end - area->start) + size,
+	    PAGE_SIZE);
+	
+	/* New heap area size */
+	void *end = (void *)
+	    ALIGN_DOWN((uintptr_t) area->start + asize, BASE_ALIGN);
+	
+	/* Check for overflow */
+	if (end < area->start)
 		return false;
-
-	if ((heap_start + size < heap_start) || (heap_end + size < heap_end))
+	
+	/* Resize the address space area */
+	int ret = as_area_resize(area->start, asize, 0);
+	if (ret != EOK)
 		return false;
 	
-	size_t heap_size = (size_t) (heap_end - heap_start);
-	
-	if ((max_heap_size != (size_t) -1) && (heap_size + size > max_heap_size))
-		return false;
-	
-	size_t pages = (size - 1) / PAGE_SIZE + 1;
-	
-	if (as_area_resize((void *) &_heap, (heap_pages + pages) * PAGE_SIZE, 0)
-	    == EOK) {
-		void *end = (void *) ALIGN_DOWN(((uintptr_t) &_heap) +
-		    (heap_pages + pages) * PAGE_SIZE, BASE_ALIGN);
-		block_init(heap_end, end - heap_end, true);
-		heap_pages += pages;
-		heap_end = end;
+	/* Add new free block */
+	block_init(area->end, (size_t) (end - area->end), true, area);
+	
+	/* Update heap area parameters */
+	area->end = end;
+	
+	return true;
+}
+
+/** Try to enlarge any of the heap areas
+ *
+ * @param size Gross size of item to allocate (bytes).
+ *
+ */
+static bool heap_grow(size_t size)
+{
+	if (size == 0)
 		return true;
-	}
-	
-	return false;
-}
-
-/** Decrease the heap area
- *
- * Should be called only inside the critical section.
- *
- * @param size Number of bytes to shrink the heap by.
- *
- */
-static void shrink_heap(void)
-{
-	// TODO
+	
+	/* First try to enlarge some existing area */
+	heap_area_t *area;
+	for (area = first_heap_area; area != NULL; area = area->next) {
+		if (area_grow(area, size))
+			return true;
+	}
+	
+	/* Eventually try to create a new area */
+	return area_create(AREA_FIRST_BLOCK(size));
+}
+
+/** Try to shrink heap space
+ *
+ * In all cases the next pointer is reset.
+ *
+ */
+static void heap_shrink(void)
+{
+	next = NULL;
 }
 
@@ -223,33 +346,6 @@
 void __malloc_init(void)
 {
-	if (!as_area_create((void *) &_heap, PAGE_SIZE,
-	    AS_AREA_WRITE | AS_AREA_READ))
+	if (!area_create(PAGE_SIZE))
 		abort();
-	
-	heap_pages = 1;
-	heap_start = (void *) ALIGN_UP((uintptr_t) &_heap, BASE_ALIGN);
-	heap_end =
-	    (void *) ALIGN_DOWN(((uintptr_t) &_heap) + PAGE_SIZE, BASE_ALIGN);
-	
-	/* Make the entire area one large block. */
-	block_init(heap_start, heap_end - heap_start, true);
-}
-
-/** Get maximum heap address
- *
- */
-uintptr_t get_max_heap_addr(void)
-{
-	futex_down(&malloc_futex);
-	
-	if (max_heap_size == (size_t) -1)
-		max_heap_size =
-		    max((size_t) (heap_end - heap_start), MAX_HEAP_SIZE);
-	
-	uintptr_t max_heap_addr = (uintptr_t) heap_start + max_heap_size;
-	
-	futex_up(&malloc_futex);
-	
-	return max_heap_addr;
 }
 
@@ -273,6 +369,6 @@
 		/* Block big enough -> split. */
 		void *next = ((void *) cur) + size;
-		block_init(next, cur->size - size, true);
-		block_init(cur, size, false);
+		block_init(next, cur->size - size, true, cur->area);
+		block_init(cur, size, false, cur->area);
 	} else {
 		/* Block too small -> use as is. */
@@ -281,43 +377,53 @@
 }
 
-/** Allocate a memory block
+/** Allocate memory from heap area starting from given block
  *
  * Should be called only inside the critical section.
- *
- * @param size  The size of the block to allocate.
- * @param align Memory address alignment.
- *
- * @return the address of the block or NULL when not enough memory.
- *
- */
-static void *malloc_internal(const size_t size, const size_t align)
-{
-	if (align == 0)
-		return NULL;
-	
-	size_t falign = lcm(align, BASE_ALIGN);
-	size_t real_size = GROSS_SIZE(ALIGN_UP(size, falign));
-	
-	bool grown = false;
-	void *result;
-	
-loop:
-	result = NULL;
-	heap_block_head_t *cur = (heap_block_head_t *) heap_start;
-	
-	while ((result == NULL) && ((void *) cur < heap_end)) {
+ * As a side effect this function also sets the current
+ * pointer on successful allocation.
+ *
+ * @param area        Heap area where to allocate from.
+ * @param first_block Starting heap block.
+ * @param final_block Heap block where to finish the search
+ *                    (may be NULL).
+ * @param real_size   Gross number of bytes to allocate.
+ * @param falign      Physical alignment of the block.
+ *
+ * @return Address of the allocated block or NULL on not enough memory.
+ *
+ */
+static void *malloc_area(heap_area_t *area, heap_block_head_t *first_block,
+    heap_block_head_t *final_block, size_t real_size, size_t falign)
+{
+	area_check((void *) area);
+	assert((void *) first_block >= (void *) AREA_FIRST_BLOCK(area));
+	assert((void *) first_block < area->end);
+	
+	heap_block_head_t *cur;
+	for (cur = first_block; (void *) cur < area->end;
+	    cur = (heap_block_head_t *) (((void *) cur) + cur->size)) {
 		block_check(cur);
+		
+		/* Finish searching on the final block */
+		if ((final_block != NULL) && (cur == final_block))
+			break;
 		
 		/* Try to find a block that is free and large enough. */
 		if ((cur->free) && (cur->size >= real_size)) {
-			/* We have found a suitable block.
-			   Check for alignment properties. */
-			void *addr = ((void *) cur) + sizeof(heap_block_head_t);
-			void *aligned = (void *) ALIGN_UP(addr, falign);
+			/*
+			 * We have found a suitable block.
+			 * Check for alignment properties.
+			 */
+			void *addr = (void *)
+			    ((uintptr_t) cur + sizeof(heap_block_head_t));
+			void *aligned = (void *)
+			    ALIGN_UP((uintptr_t) addr, falign);
 			
 			if (addr == aligned) {
 				/* Exact block start including alignment. */
 				split_mark(cur, real_size);
-				result = addr;
+				
+				next = cur;
+				return addr;
 			} else {
 				/* Block start has to be aligned */
@@ -325,15 +431,19 @@
 				
 				if (cur->size >= real_size + excess) {
-					/* The current block is large enough to fit
-					   data in including alignment */
-					if ((void *) cur > heap_start) {
-						/* There is a block before the current block.
-						   This previous block can be enlarged to compensate
-						   for the alignment excess */
-						heap_block_foot_t *prev_foot =
-						    ((void *) cur) - sizeof(heap_block_foot_t);
+					/*
+					 * The current block is large enough to fit
+					 * data in (including alignment).
+					 */
+					if ((void *) cur > (void *) AREA_FIRST_BLOCK(area)) {
+						/*
+						 * There is a block before the current block.
+						 * This previous block can be enlarged to
+						 * compensate for the alignment excess.
+						 */
+						heap_block_foot_t *prev_foot = (heap_block_foot_t *)
+						    ((void *) cur - sizeof(heap_block_foot_t));
 						
-						heap_block_head_t *prev_head =
-						    (heap_block_head_t *) (((void *) cur) - prev_foot->size);
+						heap_block_head_t *prev_head = (heap_block_head_t *)
+						    ((void *) cur - prev_foot->size);
 						
 						block_check(prev_head);
@@ -342,25 +452,38 @@
 						heap_block_head_t *next_head = ((void *) cur) + excess;
 						
-						if ((!prev_head->free) && (excess >= STRUCT_OVERHEAD)) {
-							/* The previous block is not free and there is enough
-							   space to fill in a new free block between the previous
-							   and current block */
-							block_init(cur, excess, true);
+						if ((!prev_head->free) &&
+						    (excess >= STRUCT_OVERHEAD)) {
+							/*
+							 * The previous block is not free and there
+							 * is enough free space left to fill in
+							 * a new free block between the previous
+							 * and current block.
+							 */
+							block_init(cur, excess, true, area);
 						} else {
-							/* The previous block is free (thus there is no need to
-							   induce additional fragmentation to the heap) or the
-							   excess is small, thus just enlarge the previous block */
-							block_init(prev_head, prev_head->size + excess, prev_head->free);
+							/*
+							 * The previous block is free (thus there
+							 * is no need to induce additional
+							 * fragmentation to the heap) or the
+							 * excess is small. Therefore just enlarge
+							 * the previous block.
+							 */
+							block_init(prev_head, prev_head->size + excess,
+							    prev_head->free, area);
 						}
 						
-						block_init(next_head, reduced_size, true);
+						block_init(next_head, reduced_size, true, area);
 						split_mark(next_head, real_size);
-						result = aligned;
-						cur = next_head;
+						
+						next = next_head;
+						return aligned;
 					} else {
-						/* The current block is the first block on the heap.
-						   We have to make sure that the alignment excess
-						   is large enough to fit a new free block just
-						   before the current block */
+						/*
+						 * The current block is the first block
+						 * in the heap area. We have to make sure
+						 * that the alignment excess is large enough
+						 * to fit a new free block just before the
+						 * current block.
+						 */
 						while (excess < STRUCT_OVERHEAD) {
 							aligned += falign;
@@ -371,10 +494,14 @@
 						if (cur->size >= real_size + excess) {
 							size_t reduced_size = cur->size - excess;
-							cur = (heap_block_head_t *) (heap_start + excess);
+							cur = (heap_block_head_t *)
+							    (AREA_FIRST_BLOCK(area) + excess);
 							
-							block_init(heap_start, excess, true);
-							block_init(cur, reduced_size, true);
+							block_init((void *) AREA_FIRST_BLOCK(area), excess,
+							    true, area);
+							block_init(cur, reduced_size, true, area);
 							split_mark(cur, real_size);
-							result = aligned;
+							
+							next = cur;
+							return aligned;
 						}
 					}
@@ -382,17 +509,67 @@
 			}
 		}
-		
-		/* Advance to the next block. */
-		cur = (heap_block_head_t *) (((void *) cur) + cur->size);
-	}
-	
-	if ((result == NULL) && (!grown)) {
-		if (grow_heap(real_size)) {
-			grown = true;
+	}
+	
+	return NULL;
+}
+
+/** Allocate a memory block
+ *
+ * Should be called only inside the critical section.
+ *
+ * @param size  The size of the block to allocate.
+ * @param align Memory address alignment.
+ *
+ * @return Address of the allocated block or NULL on not enough memory.
+ *
+ */
+static void *malloc_internal(const size_t size, const size_t align)
+{
+	assert(first_heap_area != NULL);
+	
+	if (align == 0)
+		return NULL;
+	
+	size_t falign = lcm(align, BASE_ALIGN);
+	size_t real_size = GROSS_SIZE(ALIGN_UP(size, falign));
+	
+	bool retry = false;
+	heap_block_head_t *split;
+	
+loop:
+	
+	/* Try the next fit approach */
+	split = next;
+	
+	if (split != NULL) {
+		void *addr = malloc_area(split->area, split, NULL, real_size,
+		    falign);
+		
+		if (addr != NULL)
+			return addr;
+	}
+	
+	/* Search the entire heap */
+	heap_area_t *area;
+	for (area = first_heap_area; area != NULL; area = area->next) {
+		heap_block_head_t *first = (heap_block_head_t *)
+		    AREA_FIRST_BLOCK(area);
+		
+		void *addr = malloc_area(area, first, split, real_size,
+		    falign);
+		
+		if (addr != NULL)
+			return addr;
+	}
+	
+	if (!retry) {
+		/* Try to grow the heap space */
+		if (heap_grow(real_size)) {
+			retry = true;
 			goto loop;
 		}
 	}
 	
-	return result;
+	return NULL;
 }
 
@@ -473,9 +650,12 @@
 	    (heap_block_head_t *) (addr - sizeof(heap_block_head_t));
 	
-	assert((void *) head >= heap_start);
-	assert((void *) head < heap_end);
-	
 	block_check(head);
 	assert(!head->free);
+	
+	heap_area_t *area = head->area;
+	
+	area_check(area);
+	assert((void *) head >= (void *) AREA_FIRST_BLOCK(area));
+	assert((void *) head < area->end);
 	
 	void *ptr = NULL;
@@ -487,29 +667,34 @@
 		/* Shrink */
 		if (orig_size - real_size >= STRUCT_OVERHEAD) {
-			/* Split the original block to a full block
-			   and a trailing free block */
-			block_init((void *) head, real_size, false);
+			/*
+			 * Split the original block to a full block
+			 * and a trailing free block.
+			 */
+			block_init((void *) head, real_size, false, area);
 			block_init((void *) head + real_size,
-			    orig_size - real_size, true);
-			shrink_heap();
+			    orig_size - real_size, true, area);
+			heap_shrink();
 		}
 		
 		ptr = ((void *) head) + sizeof(heap_block_head_t);
 	} else {
-		/* Look at the next block. If it is free and the size is
-		   sufficient then merge the two. Otherwise just allocate
-		   a new block, copy the original data into it and
-		   free the original block. */
+		/*
+		 * Look at the next block. If it is free and the size is
+		 * sufficient then merge the two. Otherwise just allocate
+		 * a new block, copy the original data into it and
+		 * free the original block.
+		 */
 		heap_block_head_t *next_head =
 		    (heap_block_head_t *) (((void *) head) + head->size);
 		
-		if (((void *) next_head < heap_end) &&
+		if (((void *) next_head < area->end) &&
 		    (head->size + next_head->size >= real_size) &&
 		    (next_head->free)) {
 			block_check(next_head);
-			block_init(head, head->size + next_head->size, false);
+			block_init(head, head->size + next_head->size, false, area);
 			split_mark(head, real_size);
 			
 			ptr = ((void *) head) + sizeof(heap_block_head_t);
+			next = NULL;
 		} else
 			reloc = true;
@@ -542,9 +727,12 @@
 	    = (heap_block_head_t *) (addr - sizeof(heap_block_head_t));
 	
-	assert((void *) head >= heap_start);
-	assert((void *) head < heap_end);
-	
 	block_check(head);
 	assert(!head->free);
+	
+	heap_area_t *area = head->area;
+	
+	area_check(area);
+	assert((void *) head >= (void *) AREA_FIRST_BLOCK(area));
+	assert((void *) head < area->end);
 	
 	/* Mark the block itself as free. */
@@ -555,12 +743,12 @@
 	    = (heap_block_head_t *) (((void *) head) + head->size);
 	
-	if ((void *) next_head < heap_end) {
+	if ((void *) next_head < area->end) {
 		block_check(next_head);
 		if (next_head->free)
-			block_init(head, head->size + next_head->size, true);
+			block_init(head, head->size + next_head->size, true, area);
 	}
 	
 	/* Look at the previous block. If it is free, merge the two. */
-	if ((void *) head > heap_start) {
+	if ((void *) head > (void *) AREA_FIRST_BLOCK(area)) {
 		heap_block_foot_t *prev_foot =
 		    (heap_block_foot_t *) (((void *) head) - sizeof(heap_block_foot_t));
@@ -572,8 +760,9 @@
 		
 		if (prev_head->free)
-			block_init(prev_head, prev_head->size + head->size, true);
-	}
-	
-	shrink_heap();
+			block_init(prev_head, prev_head->size + head->size, true,
+			    area);
+	}
+	
+	heap_shrink();
 	
 	futex_up(&malloc_futex);
Index: uspace/lib/c/generic/private/libc.h
===================================================================
--- uspace/lib/c/generic/private/libc.h	(revision ae6f303748db0f9a242fb1a15affe2c3ee62e621)
+++ uspace/lib/c/generic/private/libc.h	(revision 0b378820b4861f67ea1335ef6260a5c98a59c64c)
@@ -36,6 +36,7 @@
 #define LIBC_PRIVATE_LIBC_H_
 
+extern void __entry(void);
+extern void __main(void *) __attribute__((noreturn));
 extern int main(int, char *[]);
-extern void __main(void *) __attribute__((noreturn));
 
 #endif
Index: uspace/lib/c/include/malloc.h
===================================================================
--- uspace/lib/c/include/malloc.h	(revision ae6f303748db0f9a242fb1a15affe2c3ee62e621)
+++ uspace/lib/c/include/malloc.h	(revision 0b378820b4861f67ea1335ef6260a5c98a59c64c)
@@ -38,6 +38,4 @@
 #include <sys/types.h>
 
-extern uintptr_t get_max_heap_addr(void);
-
 extern void *malloc(const size_t size)
     __attribute__((malloc));
