Трудности чтения энергозависимой памяти.C++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Трудности чтения энергозависимой памяти.

Сообщение Anonymous »

У меня есть код, который хорошо работает при компиляции с помощью gcc, но не работает корректно при компиляции с clang. Я обнаружил проблему в чтении энергозависимой памяти (на микроконтроллере). Выполнив сборку, я обнаружил, что память, связанная с pma_address, считывается в регистр, но значения, установленные в регистре, никогда не используются. Таким образом, handle_setup_packet предположительно никогда не вызывается, потому что оптимизатор определил, что буфер никогда не изменится. Если превратить buffer_out в изменчивый uint8_t*, код будет работать правильно. Но я не понимаю, почему в этом случае он должен быть нестабильным. Я думаю, что одной изменчивой переменной будет достаточно, чтобы убедить компилятор, что на буфер стоит обратить внимание. Мне интересно, в чем моя логическая ошибка в следующем коде:

Код: Выделить всё

void read_pma(uint8_t byte_count, volatile uint16_t * pma_address, uint8_t *buffer_out) {
int count_received_16 = (byte_count + 1) >> 1;
for(int i=0; ibuffer[0].EP_RX, buffer);
handle_setup_packet(reinterpret_cast(buffer));
}
Обновления
Я добавляю дополнительную информацию для рассмотрения комментариев. Из предложений в комментариях я узнал больше о строгом псевдониме и обнаружил, что, по моему мнению, является основной проблемой. Компилятор clang 20.1.0, предоставленный ARM: https://github.com/arm/arm-toolchain с параметрами -target=armv7m-none-eabi -O3 -flto. Созданная сборка довольно велика из-за развертывания цикла, но обычно существует несколько разделов, как показано ниже, где она несколько раз загружает ячейку памяти pma_address и неоднократно записывает в рабочий регистр.

Код: Выделить всё

;         ((uint16_t *) buffer_out)[i] = pma_address[i];
10000776: f835 3c1e     ldrh    r3, [r5, #-30]
1000077a: f835 3c1c     ldrh    r3, [r5, #-28]
1000077e: f835 3c1a     ldrh    r3, [r5, #-26]
10000782: f835 3c18     ldrh    r3, [r5, #-24]
10000786: f835 3c16     ldrh    r3, [r5, #-22]
1000078a: f835 3c14     ldrh    r3, [r5, #-20]
Я нашел несколько способов заставить его сгенерировать предполагаемую сборку ниже:

Код: Выделить всё

;         ((uint16_t *) buffer_out)[i] = pma_address[i];
8004370: 885f          ldrh    r7, [r3, #0x2]
8004372: eb00 0144     add.w   r1, r0, r4, lsl #1
8004376: f8a1 704d     strh.w  r7, [r1, #0x4d]
800437a: eb08 0744     add.w   r7, r8, r4, lsl #1
800437e: f8b7 20a2     ldrh.w  r2, [r7, #0xa2]
;     for(int i=0; i> 1;
for(int i=0; i> 8) & 0xFF;
}
}

fun() {
read_pma(byte_count, USBPMA->buffer[0].EP_RX, buffer);
usb_control_request ctrl_req {};
std::memcpy(&ctrl_req, buffer, sizeof(usb_control_request));
handle_setup_packet(&ctrl_req);
}

Я пытался, но не смог создать версию этого кода в Godbolt Compiler Explorer и смог получить непредвиденное поведение только в контексте полной программы. Главное, что меня удивило в отладке, это то, что при LTO компилятор может полностью игнорировать функцию handle_setup_packet из-за нарушения псевдонимов. Я проверил это, поместив недопустимый код в эту функцию asm("valid_op;"); в тот код, который не генерировал ошибок при компиляции в режиме LTO.

Подробнее здесь: https://stackoverflow.com/questions/797 ... ile-memory
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»