Не выровненный 8-байтовый доступ к памяти вызывает нарушение доступа к памяти на iPhone 3GS с iOS 4.0 - PullRequest
2 голосов
/ 09 августа 2010

рассмотрим следующее приложение Objective-C ++ для iPhone (TestMemAppDelegate.mm). Вылетает с EXC_BAD_ACCESS на iPhone (3GS с iOS 4.0). Он отлично работает в симуляторе. Очевидно, это выравнивание памяти, потому что оно отлично работает на iPhone, если структура «DataA» начинается на границе 8 байт.

Кто-нибудь может объяснить причину? Это что-то с архитектурой ARM? ARM компилятор?

@implementation TestMemAppDelegate


typedef struct DataA
{
 float    x;
 unsigned char  y;
};


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    

 char* mem1 = (char*)malloc(4096);

 DataA* ptrA = (DataA*)(mem1 + 1); // Here we shift the alignment
 ptrA->x = 10.0f;
 printf("A: %.2f\n", ptrA->x); // Here it crashes



    // Add the view controller's view to the window and display.
    [window addSubview:viewController.view];
    [window makeKeyAndVisible];

    return YES;
}


@end

Ответы [ 3 ]

6 голосов
/ 09 августа 2010

Да, это проблема выравнивания. Число с плавающей точкой должно быть выровнено в 4 байта. Процессор Intel x86 допускает несогласованный доступ (но при снижении производительности). На ARM это не разрешено и генерирует ошибку, которую вы видите.

0 голосов
/ 09 августа 2010

Я думаю, вы обнаружите, что это нарушение стандарта C (и, вероятно, C99). malloc () гарантирует возврат памяти с соответствующим выравниванием, так что вы можете сделать что-то вроде

struct DataA * foo = (struct DataA *)malloc(sizeof(struct DataA));
foo->x = 10;

Однако существуют требования по выравниванию, поэтому не гарантируется, что вы можете произвольно изменить указатель и заставить его работать.

Тем не менее, ОС может разрешить неправильный доступ к памяти, перехватывая исключение и выполняя доступ к памяти вручную. На PowerPC ЦП обрабатывает смещенные целочисленные обращения, но ожидает, что ОС будет обрабатывать смещенные обращения с плавающей запятой.

Наконец, вам может удастся заставить его работать, используя расширение GCC __attribute__((packed)):

struct foo {
  ...
} __attribute__((packed));

Это имеет два эффекта:

  • Переменные в структуре имеют выравнивание 1 (это может изменить макет памяти вашей структуры)
  • Структура имеет выравнивание 1 (т. Е. Компилятор больше не будет выравнивать его, например, когда вы вставляете его в другую структуру)

Это может означать, что GCC генерирует код, необходимый для выполнения некорректной загрузки. Но почему вы хотите это сделать?

0 голосов
/ 09 августа 2010

Число с плавающей запятой обычно должно быть выровнено не менее 4 байтов.

...