Нашёл в условном ящике стола мобильник Motorola SLVR L6, которому почти 20 лет. Протёр пыль, зарядил батарейку «лягушкой» – до сих пор рабочий чертяка. Оказалось, что под него можно кодить не только на унылом подмножестве Java – J2ME, но и на православной сишке и даже плюсцах. Скачал кросс-компилятор и SDK, доступные как под Linux, так и под Windows и решил написать пару GUI-программок и подёргать функции из прошивки телефона, но столкнулся с одной странной особенностью, про которую хочу уточнить у специалистов.
Есть у меня следующий минимально-неработающий пример и функция wtf_foo()
, которую по хорошему нужно инлайнить, но похоже что в кросс-компиляторе вообще не работают инлайны:
#define SWAP_UINT32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | ((x) << 24))
static uint8_t bmp_header[70] = {
0x42, 0x4D, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x38, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x10, 0x00, 0x03, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0x1F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static void wtf_foo(uint8_t *start_address, uint32_t start_offset, uint32_t value) {
*((uint32_t *) &start_address[start_offset]) = value;
/* start_address[start_offset + 0x00] = (value >> 0) & 0x000000FF; */
/* start_address[start_offset + 0x01] = (value >> 8) & 0x000000FF; */
/* start_address[start_offset + 0x02] = (value >> 16) & 0x000000FF; */
/* start_address[start_offset + 0x03] = (value >> 24) & 0x000000FF; */
}
void main(void) {
print_hex();
wtf_foo(bmp_header, 0x02, SWAP_UINT32(41030));
wtf_foo(bmp_header, 0x12, SWAP_UINT32(128));
wtf_foo(bmp_header, 0x16, SWAP_UINT32(160));
wtf_foo(bmp_header, 0x22, SWAP_UINT32(40960));
print_hex();
}
Результаты исполнения кода:
42 4D |FF FF FF FF| 00 00 00 00 46 00 00 00 38 00
00 00 |FF FF FF FF FF FF FF FF| 01 00 10 00 03 00
00 00 |FF FF FF FF| 00 00 00 00 00 00 00 00 00 00 (1)
00 00 00 00 00 00 00 F8 00 00 E0 07 00 00 1F 00
00 00 00 00 00 00
42 4D |46 A0 00 00| 00 00 00 00 46 00 00 00 38 00
00 00 |80 00 00 00 A0 00 00 00| 01 00 10 00 03 00
00 00 |00 A0 00 00| 00 00 00 00 00 00 00 00 00 00 (2)
00 00 00 00 00 00 00 F8 00 00 E0 07 00 00 1F 00
00 00 00 00 00 00
|46 A0 00 00| FF FF 00 00 00 00 46 00 00 00 38 00
|80 00 00 00 A0 00 00 00| FF FF 01 00 10 00 03 00
|00 A0 00 00| FF FF 00 00 00 00 00 00 00 00 00 00 (3)
00 00 00 00 00 00 00 F8 00 00 E0 07 00 00 1F 00
00 00 00 00 00 00
- Оригинальный массив без изменений.
- Результат работы кода на x86_64, little-endian, хост.
- Результат работы кода на ARMv4T, big-endian, целевая железка.
Примечание: Макрос SWAP_UINT32()
используется только на целевом устройстве. Код функции wtf_foo()
который закомментирован отрабатывает везде одинаково и нормально.
Не понимаю откуда тут берётся сдвиг влево, почему он именно на два байта? Хочется разобраться в чём именно причина этой ошибки? Где-то моя невнимательность при работе с ARM и big-endian или что-то другое, к примеру, баг в компиляторе?
Дополнительная информация, если кому интересно:
Компилятор:
ARM C/C++ Compiler, ADS1.2 [Build 848]
Thumb C/C++ Compiler, ADS1.2 [Build 848]
Железо:
SOC: Freescale/Motorola Neptune LTE
CPU: ARM7TDMI | ARMv4T | big-endian | 52 MHz
RAM: (4) 8 MB, 1.5 MB free.
DSP: 104 MHz StarCore DSP
Операционная система:
P2K OS: Synergy Environment + VRTXmc RTOS Kernel.
P.S. Внутри девайса не Linux, но есть какой-то кастрированный libc и UNIX-подобная регистрозависимая файловая система.