iOS NSInvocation setArgument: atIndex: не работает со структурой в сборках ARM

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

Я использую 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



person Sam    schedule 01.04.2012    source источник


Ответы (1)


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

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

person JeremyP    schedule 05.04.2012