Though I have already marked an answer as accepted, and offered a bounty at the time, I have since found the true answer I was searching for and realised my question wasn't very clear - primarily because I didn't know what to ask.
How to interact with @autoreleasepool:
When the compiler comes across an @autoreleasepool { } block, it automatically inserts two function calls. At the opening of the block it inserts the C function call:
void *_objc_autoreleasePoolPush(void);
At the close of the @autoreleasepool block (including when a return or break is encountered within - but NOT when an exception is thrown according to the LLVM docs) the compiler inserts the C function call:
_objc_autoreleasePoolPop(void *ctxt); // ctxt is Apple's label for the param
I believe the void *ctxt parameter is an indicator of where the current @autoreleasepool started (really only useful in Apple's implementation - see here). In any case I found it can easily be ignored in custom implementations.
The -autorelease selector:
Essentially the methodology is this:
- Create (if outermost block) or mark (if inner block) an autorelease pool object (in C or C++) in 
_objc_autoreleasePoolPush(). It seems easiest to me to use a Stack data structure for this but YMMV. 
- Ensure this object is in scope within the 
-autorelease selector, or you have a fail-safe way of accessing it. 
- Add the object to the autorelease pool object (in whatever way that may be) inside 
-autorelease. 
- In 
_objc_autoreleasePoolPop(void *), send the -release message to every item in the autorelease pool object until the marker set in _objc_autoreleasePoolPush() is reached (or you reach the bottom of the pool). Then do any additional required cleanup. 
Final notes on threading:
Objective-C @autoreleasepools are supposed to be thread-local. That is, each thread has its own (if it requires one). As a result, _objc_autoreleasePoolPush() must have some way of determining whether the current thread already has an active autorelease pool and create the object if it does not.
Similarly, this is why, when creating a thread, the thread must first open an @autoreleasepool { } block before it does anything else (in Objective-C), and the final thing it must do is close that @autoreleasepool block (implicitly through break or return or with explicit fall-through).
Three final observations:
- If you wish to implement your own autorelease pool object, you will need some form of thread-local storage to store it.
 
- That last point about threading is why every Objective-C program must begin with an 
@autoreleasepool { } block in main(). 
- This is why Apple ask you to use the 
NSThread class and GCD rather than DIY threading - they take care of all of this for you!