Skip to content

Commit 9490b1b

Browse files
author
theraven
committed
Implement ARM EH support, fix objc_msgSend() to work on ARM.
1 parent 2a3a93e commit 9490b1b

8 files changed

+489
-197
lines changed

GNUmakefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ LIBOBJC = libobjc
3434
LIBOBJCLIBNAME = objc
3535
LIBOBJCXX = libobjcxx
3636

37-
LIBRARY_NAME = ${LIBOBJC} ${LIBOBJCXX}
37+
LIBRARY_NAME = ${LIBOBJC}
3838

3939
${LIBOBJC}_OBJC_FILES = \
4040
NSBlocks.m\

Test/objc_msgSend.m

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#include <class.h>
77
#include <stdarg.h>
88

9+
//#define assert(x) if (!(x)) { printf("Failed %d\n", __LINE__); }
10+
911
id objc_msgSend(id, SEL, ...);
1012

1113
typedef struct { int a,b,c,d,e; } s;
@@ -48,6 +50,7 @@ + (void)printf: (const char*)str, ...
4850

4951
vasprintf(&s, str, ap);
5052
va_end(ap);
53+
//fprintf(stderr, "String: '%s'\n", s);
5154
assert(strcmp(s, "Format string 42 42.000000\n") ==0);
5255
}
5356
+ (void)initialize
@@ -68,7 +71,7 @@ int main(void)
6871
assert((TestCls == e) && "Exceptions propagate out of +initialize");
6972
exceptionThrown = 1;
7073
}
71-
assert(exceptionThrown);
74+
assert(exceptionThrown && "An exception was thrown");
7275
assert((id)0x42 == objc_msgSend(TestCls, @selector(foo)));
7376
objc_msgSend(TestCls, @selector(nothing));
7477
objc_msgSend(TestCls, @selector(missing));

eh_personality.c

+99-26
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,68 @@ typedef enum
4848
handler_class
4949
} handler_type;
5050

51+
/**
52+
* Saves the result of the landing pad that we have found. For ARM, this is
53+
* stored in the generic unwind structure, while on other platforms it is
54+
* stored in the Objective-C exception.
55+
*/
56+
static void saveLandingPad(struct _Unwind_Context *context,
57+
struct _Unwind_Exception *ucb,
58+
struct objc_exception *ex,
59+
int selector,
60+
dw_eh_ptr_t landingPad)
61+
{
62+
#ifdef __arm__
63+
// On ARM, we store the saved exception in the generic part of the structure
64+
ucb->barrier_cache.sp = _Unwind_GetGR(context, 13);
65+
ucb->barrier_cache.bitpattern[1] = (uint32_t)selector;
66+
ucb->barrier_cache.bitpattern[3] = (uint32_t)landingPad;
67+
#else
68+
// Cache the results for the phase 2 unwind, if we found a handler
69+
// and this is not a foreign exception. We can't cache foreign exceptions
70+
// because we don't know their structure (although we could cache C++
71+
// exceptions...)
72+
if (ex)
73+
{
74+
ex->handlerSwitchValue = selector;
75+
ex->landingPad = landingPad;
76+
}
77+
#endif
78+
}
79+
80+
/**
81+
* Loads the saved landing pad. Returns 1 on success, 0 on failure.
82+
*/
83+
static int loadLandingPad(struct _Unwind_Context *context,
84+
struct _Unwind_Exception *ucb,
85+
struct objc_exception *ex,
86+
unsigned long *selector,
87+
dw_eh_ptr_t *landingPad)
88+
{
89+
#ifdef __arm__
90+
*selector = ucb->barrier_cache.bitpattern[1];
91+
*landingPad = (dw_eh_ptr_t)ucb->barrier_cache.bitpattern[3];
92+
return 1;
93+
#else
94+
if (ex)
95+
{
96+
*selector = ex->handlerSwitchValue;
97+
*landingPad = ex->landingPad;
98+
return 0;
99+
}
100+
return 0;
101+
#endif
102+
}
103+
104+
static inline _Unwind_Reason_Code continueUnwinding(struct _Unwind_Exception *ex,
105+
struct _Unwind_Context *context)
106+
{
107+
#ifdef __arm__
108+
if (__gnu_unwind_frame(ex, context) != _URC_OK) { return _URC_FAILURE; }
109+
#endif
110+
return _URC_CONTINUE_UNWIND;
111+
}
112+
51113
static void cleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception *e)
52114
{
53115
/*
@@ -92,6 +154,7 @@ void objc_exception_throw(id object)
92154
{
93155
_objc_unexpected_exception(object);
94156
}
157+
fprintf(stderr, "Throw returned %d\n",(int) err);
95158
abort();
96159
}
97160

@@ -199,15 +262,33 @@ static handler_type check_action_record(struct _Unwind_Context *context,
199262
return handler_none;
200263
}
201264

265+
_Unwind_Reason_Code
266+
__gnu_objc_personality_v01(_Unwind_State state,
267+
struct _Unwind_Exception *ue_header,
268+
struct _Unwind_Context *context)
269+
{
270+
fprintf(stderr, "LSDA: %p\n", (void*)_Unwind_GetLanguageSpecificData(context));
271+
unsigned char *lsda_addr = (void*)_Unwind_GetLanguageSpecificData(context);
272+
fprintf(stderr, "Encoding: %x\n", (int)*lsda_addr);
273+
return 0;
274+
275+
}
276+
typedef uint32_t _uw;
277+
202278
/**
203279
* The Objective-C exception personality function.
204280
*/
205-
_Unwind_Reason_Code __gnu_objc_personality_v0(int version,
206-
_Unwind_Action actions,
207-
uint64_t exceptionClass,
208-
struct _Unwind_Exception *exceptionObject,
209-
struct _Unwind_Context *context)
210-
{
281+
BEGIN_PERSONALITY_FUNCTION(__gnu_objc_personality_v0)
282+
fprintf(stderr, "Personality function called\n");
283+
284+
_uw *ptr = (_uw *) exceptionObject->pr_cache.ehtp;
285+
/* Skip the personality routine address. */
286+
ptr++;
287+
/* Skip the unwind opcodes. */
288+
ptr += (((*ptr) >> 24) & 0xff) + 1;
289+
fprintf(stderr, "Maybe this is the LSDA? 0x%x\n", ptr);
290+
291+
211292
// This personality function is for version 1 of the ABI. If you use it
212293
// with a future version of the ABI, it won't know what to do, so it
213294
// reports a fatal error and give up before it breaks anything.
@@ -216,8 +297,9 @@ _Unwind_Reason_Code __gnu_objc_personality_v0(int version,
216297
return _URC_FATAL_PHASE1_ERROR;
217298
}
218299
struct objc_exception *ex = 0;
219-
220-
//char *cls = (char*)&exceptionClass;
300+
#ifndef fprintf
301+
char *cls = (char*)&exceptionClass;
302+
#endif
221303
fprintf(stderr, "Class: %c%c%c%c%c%c%c%c\n", cls[7], cls[6], cls[5], cls[4], cls[3], cls[2], cls[1], cls[0]);
222304

223305
// Check if this is a foreign exception. If it is a C++ exception, then we
@@ -266,6 +348,7 @@ _Unwind_Reason_Code __gnu_objc_personality_v0(int version,
266348
fprintf(stderr, "Foreign class: %p\n", thrown_class);
267349
}
268350
unsigned char *lsda_addr = (void*)_Unwind_GetLanguageSpecificData(context);
351+
fprintf(stderr, "LSDA: %p\n", lsda_addr);
269352

270353
// No LSDA implies no landing pads - try the next frame
271354
if (0 == lsda_addr) { return _URC_CONTINUE_UNWIND; }
@@ -276,6 +359,7 @@ _Unwind_Reason_Code __gnu_objc_personality_v0(int version,
276359

277360
if (actions & _UA_SEARCH_PHASE)
278361
{
362+
fprintf(stderr, "Search phase...\n");
279363
struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr);
280364
action = dwarf_eh_find_callsite(context, &lsda);
281365
handler_type handler = check_action_record(context, foreignException,
@@ -286,13 +370,7 @@ _Unwind_Reason_Code __gnu_objc_personality_v0(int version,
286370
((handler == handler_catchall_id) && !foreignException) ||
287371
(handler == handler_catchall))
288372
{
289-
// Cache the results for the phase 2 unwind, if we found a handler
290-
// and this is not a foreign exception.
291-
if (ex)
292-
{
293-
ex->handlerSwitchValue = selector;
294-
ex->landingPad = action.landing_pad;
295-
}
373+
saveLandingPad(context, exceptionObject, ex, selector, action.landing_pad);
296374
fprintf(stderr, "Found handler! %d\n", handler);
297375
return _URC_HANDLER_FOUND;
298376
}
@@ -353,8 +431,7 @@ _Unwind_Reason_Code __gnu_objc_personality_v0(int version,
353431
else
354432
{
355433
// Restore the saved info if we saved some last time.
356-
action.landing_pad = ex->landingPad;
357-
selector = ex->handlerSwitchValue;
434+
loadLandingPad(context, exceptionObject, ex, &selector, &action.landing_pad);
358435
object = ex->object;
359436
free(ex);
360437
}
@@ -367,12 +444,9 @@ _Unwind_Reason_Code __gnu_objc_personality_v0(int version,
367444
return _URC_INSTALL_CONTEXT;
368445
}
369446

370-
_Unwind_Reason_Code __gnustep_objcxx_personality_v0(int version,
371-
_Unwind_Action actions,
372-
uint64_t exceptionClass,
373-
struct _Unwind_Exception *exceptionObject,
374-
struct _Unwind_Context *context)
375-
{
447+
// FIXME!
448+
#ifndef __arm__
449+
BEGIN_PERSONALITY_FUNCTION(__gnustep_objcxx_personality_v0)
376450
if (exceptionClass == objc_exception_class)
377451
{
378452
struct objc_exception *ex = (struct objc_exception*)
@@ -391,7 +465,6 @@ _Unwind_Reason_Code __gnustep_objcxx_personality_v0(int version,
391465
exceptionObject = ex->cxx_exception;
392466
exceptionClass = cxx_exception_class;
393467
}
394-
return __gxx_personality_v0(version, actions, exceptionClass,
395-
exceptionObject, context);
468+
return CALL_PERSONALITY_FUNCTION(__gxx_personality_v0);
396469
}
397-
470+
#endif

objc_msgSend.arm.S

+13-10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#define DATA_OFFSET 12
55
#define SLOT_OFFSET 16
66
.syntax unified
7+
.fpu neon
78

89
// Macro for testing: logs a register value to standard error
910
.macro LOG reg
@@ -14,14 +15,15 @@
1415
.endm
1516

1617
.macro MSGSEND receiver, sel
17-
.cfi_startproc
18+
.fnstart
1819
teq \receiver, 0
1920
beq 4f // Skip everything if the receiver is nil
2021
push {r4-r6} // We're going to use these three as
21-
.cfi_adjust_cfa_offset 12 // scratch registers, so save them now.
22-
.cfi_rel_offset r4, 0 // These are callee-save, so the unwind library
23-
.cfi_rel_offset r5, 4 // must be able to restore them, so we need CFI
24-
.cfi_rel_offset r6, 8 // directives for them, but not for any other pushes
22+
.save {r4-r6}
23+
// scratch registers, so save them now.
24+
// These are callee-save, so the unwind library
25+
// must be able to restore them, so we need CFI
26+
// directives for them, but not for any other pushes
2527
tst \receiver, SMALLOBJ_MASK // Sets Z if this is not a small int
2628

2729

@@ -73,21 +75,22 @@
7375
mov r1, 0
7476
mov pc, lr
7577
5: // Slow lookup
76-
push {r0-r3, lr} // Save anything that will be clobbered by the call
78+
push {r0-r4, lr} // Save anything that will be clobbered by the call
79+
.save {r0-r4, lr}
80+
7781

7882
push {\receiver} // &self, _cmd in arguments
79-
mov r0, sp
83+
.save {\receiver}
8084
mov r1, \sel
8185

82-
.cfi_adjust_cfa_offset 24 // pushed 6 more 4-byte words onto the stack.
8386
bl slowMsgLookup(PLT) // This is the only place where the CFI directives have to be accurate...
8487
mov ip, r0 // IMP -> ip
8588

8689
pop {r5} // restore (modified) self to r5
87-
pop {r0-r3, lr} // Load clobbered registers
90+
pop {r0-r4, lr} // Load clobbered registers
8891
mov \receiver, r5
8992
b 3b
90-
.cfi_endproc
93+
.fnend
9194
.endm
9295

9396
.globl objc_msgSend

objcxx_eh.h

+1-6
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,7 @@ struct _Unwind_Exception *objc_init_cxx_exception(void *thrown_exception);
1919
* The GNU C++ exception personality function, provided by libsupc++ (GNU) or
2020
* libcxxrt (PathScale).
2121
*/
22-
__attribute__((weak))
23-
_Unwind_Reason_Code __gxx_personality_v0(int version,
24-
_Unwind_Action actions,
25-
uint64_t exceptionClass,
26-
struct _Unwind_Exception *exceptionObject,
27-
struct _Unwind_Context *context);
22+
__attribute__((weak)) DECLARE_PERSONALITY_FUNCTION(__gxx_personality_v0);
2823
/**
2924
* Frees an exception object allocated by __cxa_allocate_exception(). Part of
3025
* the Itanium C++ ABI.

0 commit comments

Comments
 (0)