Refactor linker mapping/unmapping logic
As @angerman recently noted in !4310 (comment 313170), the current state of the linker is ripe for bugs. In particular, we have at least 4 different codepaths for allocating/mapping various parts of the image:
malloc
- the m32 allocator
-
mmap
of anonymous memory -
mmap
of image file
To make matters worse, the logic for choosing which mechanism is used for a given region is mirrored throughout the linker, with codepaths for allocation, protection, and freeing which all need to match. Inconsistencies here can and do cause bugs.
To solve this, I propose that we introduce a new abstraction, Region
. Conceptually, Region
is a sum. To borrow Haskell syntax:
data Region
= M32RXRegion Addr
-- ^ Pages allocated via the ObjectCode's R|X M32 allocator.
| M32RWRegion Addr
-- ^ Pages allocated via the ObjectCode's R|W M32 allocator.
| AnonMmapRegion Addr Size Protection
-- ^ Pages of anonymous memory with the given desired protection mapped via mmap
| ImageMmapRegion Addr Size Offset Protection
-- ^ Pages of the image with the given desired protection mapped via mmap
| MallocRegion Addr
-- ^ Pages of read/write memory allocated via malloc
-- | How should the region be protected when we have finished resolving the object?
regionDesiredProtection :: Region -> Protection
regionDesiredProtection (M32RXRegion _) = ReadExec
regionDesiredProtection (M32RWRegion _) = ReadWrite
regionDesiredProtection (AnonMmapRegion _ _ p) = p
regionDesiredProtection (ImageMmapRegion _ _ _ p) = p
regionDesiredProtection (MallocRegion _) = ReadWrite
protectRegion :: Region -> IO ()
freeRegion :: Region -> IO ()
The idea here is that all mapping will occur via the region abstraction and each ObjectCode
will have a list of regions. All regions will be initially mapped as RW, but then protected (by protectRegion
) with regionDesiredProtection
after resolution has finished. Furthermore, cleaning up the mappings associated with an object is simply a matter of walking the region list and calling freeRegion
on each.
This should be able to handle all of the various mapping types that we current handle by way of spaghetti in a single, consistent framework.