2012-04-01 6 views
1

У меня есть странная проблема с установкой аргумента NSInvocation со структурой, которая содержит двойной или любой 64-разрядный тип, который не выровнен (я его компенсировал char в начале структуры). Проблема в том, что некоторые байты очищаются после установки аргумента. Эта проблема возникает на ARM7, но не в симуляторе iOS.iOS NSInvocation setArgument: atIndex: не работает со структурой в строках ARM

Я использую LLVM 3.0 и Xcode 4.2

Вот мой код и результаты испытаний:

NSInvocation + Extension.h

@interface NSInvocation (Extension) 

+ (NSInvocation*) invocationWithTarget: (id)aTarget 
           selector: (SEL)aSelector 
         retainArguments: (BOOL)aRetainArguments, ...; 

- (void) setArguments: (va_list)aArgList; 
- (void) setArguments: (va_list)aArgList atIndex: (NSInteger)aIndex; 

@end // NSInvocation (Extension) 

NSInvocation + Extension.m

#import <objc/runtime.h> 

#import "NSInvocation+Extension.h" 


@implementation NSInvocation (Extension) 

+ (NSInvocation*) invocationWithTarget: (id)aTarget 
           selector: (SEL)aSelector 
         retainArguments: (BOOL)aRetainArguments, ... 
{ 
    NSMethodSignature* signature = [aTarget methodSignatureForSelector: aSelector]; 
    NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: signature]; 

    if (aRetainArguments) 
    { 
     [invocation retainArguments]; 
    } 
    [invocation setTarget: aTarget]; 
    [invocation setSelector: aSelector]; 

    va_list argList; 
    va_start(argList, aRetainArguments); 
    [invocation setArguments: argList]; 
    va_end(argList); 

    return invocation; 
} 

- (void) setArguments: (va_list)aArgList 
{ 
    [self setArguments: aArgList atIndex: 0]; 
} 

- (void) setArguments: (va_list)aArgList atIndex: (NSInteger)aIndex 
{ 
    // Arguments are aligned on machine word boundaries 
    const NSUInteger KOffset = sizeof(size_t) - 1; 

    UInt8* argPtr = (UInt8*)aArgList; 
    NSMethodSignature* signature = [self methodSignature]; 

    // Indices 0 and 1 indicate the hidden arguments self and _cmd respectively. 
    for (int index = aIndex + 2; index < [signature numberOfArguments]; ++index) 
    { 
     const char* type = [signature getArgumentTypeAtIndex: index]; 
     NSUInteger size = 0; 
     NSGetSizeAndAlignment(type, &size, NULL); 
     [self setArgument: argPtr atIndex: index]; 
     argPtr += (size + KOffset) & ~KOffset; 
    } 
} 

@end // NSInvocation (Extension) 

метод Объявите для вызова и структура данных

- (void) arg1: (char)aArg1 arg2: (char)aArg2 arg3: (TEST)aArg3 arg4: (char)aArg4; 

typedef struct test { 
    char c; 
    double s; 
    char t; 
    void* b; 
    char tu; 
} TEST; 

телефонный код

TEST df = { 'A', 12345678.0, 'B', (void*)2, 'C' }; 

char buf[100] = {0}; 

NSInvocation* ik = [NSInvocation invocationWithTarget: self selector: @selector(arg1:arg2:arg3:arg4:) retainArguments: NO, '1', '2', df, '3']; 
[ik getArgument: &buf atIndex: 4]; 

Содержание BUF на ARM7 (байт 8, 9, 10 и 11 набор для ноль, который испортил двойное значение)

41 00 00 00 00 00 00 00 29 8C 67 41 42 00 00 00 02 00 00 00 43 00 00 00

Содержание BUF на i386 тренажере (как ожидалось)

41 00 00 00 00 00 00 C0 29 8C 67 41 42 00 00 00 02 00 00 00 43 00 00 00


ответ

2

Первая мысль, что вы действительно должны использовать va_arg для доступа последовательных аргументов в VARIADIC списка аргументов. Вы не можете просто предположить, что аргументы упорядочены в приятном непрерывном фрагменте памяти, как вы. Во-первых, ARM ABI говорит, что первые четыре аргумента передаются в регистры.

Va_list необязательно должен быть просто указателем, это непрозрачный тип. Ваш приведение к uint8_t * почти наверняка недействительно.