Мне кажется, что я сталкиваюсь с ошибкой компилятора при создании очень большого проекта. Проблематичная генерация кода наблюдается только тогда, когда код компилируется с -O1 (а не с -O0 или -O2).
Проблема заключается в вызове функции, которая является оболочкой для find_if. Эта функция принимает в качестве входных данных пустой вектор, что должно привести к немедленному возвращению find_if.
Код выглядит примерно так:
void LookUpEvalResultFun(some arguments) {
empty vector declaration
some simple code handling the arguments
call the function that is wrapper to find_if
}
В случае, если код не работает должным образом, ассемблер выглядит следующим образом:
0x00eab0dc <+0>: strd r4, [sp, #-36]! ; 0xffffffdc
0x00eab0e0 <+4>: strd r6, [sp, #8]
0x00eab0e4 <+8>: strd r8, [sp, #16]
0x00eab0e8 <+12>: strd r10, [sp, #24]
0x00eab0ec <+16>: str lr, [sp, #32]
0x00eab0f0 <+20>: add r11, sp, #32
0x00eab0f4 <+24>: sub sp, sp, #132 ; 0x84
0x00eab0f8 <+28>: ldr r3, [r0]
0x00eab0fc <+32>: ldr r3, [r3, #24]
0x00eab100 <+36>: blx r3
0x00eab104 <+40>: movw r4, #21700 ; 0x54c4
0x00eab108 <+44>: movt r4, #373 ; 0x175
0x00eab10c <+48>: mov r3, #0
0x00eab110 <+52>: strb r3, [sp]
0x00eab114 <+56>: ldr r2, [r4, #52] ; 0x34
0x00eab118 <+60>: ldr r0, [r4, #48] ; 0x30
0x00eab11c <+64>: bl 0xd9c4a0 <mangled name for find_if>
mangled name for find_if:
0x00d9c4a0 <+0>: strd r4, [sp, #-32]! ; 0xffffffe0
0x00d9c4a4 <+4>: strd r6, [sp, #8]
0x00d9c4a8 <+8>: strd r8, [sp, #16]
0x00d9c4ac <+12>: str r11, [sp, #24]
0x00d9c4b0 <+16>: str lr, [sp, #28]
0x00d9c4b4 <+20>: add r11, sp, #28
0x00d9c4b8 <+24>: mov r9, r1
0x00d9c4bc <+28>: mov r7, r0
0x00d9c4c0 <+32>: rsb r8, r0, r1
0x00d9c4c4 <+36>: asr r8, r8, #6
0x00d9c4c8 <+40>: movw r3, #43691 ; 0xaaab
0x00d9c4cc <+44>: movt r3, #43690 ; 0xaaaa
0x00d9c4d0 <+48>: mul r8, r3, r8
0x00d9c4d4 <+52>: asr r8, r8, #2
0x00d9c4d8 <+56>: cmp r8, #0
0x00d9c4dc <+60>: ble 0xd9c558 <_ZSt9__find_ifIN9__gnu_cxx17__normal_iterator...>
Инструкции ниже:
0x00eab114 <+56>: ldr r2, [r4, #52] ; 0x34
0x00eab118 <+60>: ldr r0, [r4, #48] ; 0x30
против
0x00d9c4b8 <+24>: mov r9, r1
0x00d9c4bc <+28>: mov r7, r0
показывает, что в функции-обертке R2 загружается vector.end (), а find_if ожидает найти vector.end () в R1.
Что более интересно, независимо от того, как код компилируется относительно уровней оптимизации, это следующее (при компиляции каждого файла отдельно с -c).
1244: e3a00000 mov r0, #0
template<typename _Iterator, typename _Predicate>
inline _Iterator
__find_if(_Iterator __first, _Iterator __last, _Predicate __pred)
{
return __find_if(__first, __last, __pred, std::__iterator_category(__first));
1248: e3a03000 mov r3, #0
124c: e5cd3000 strb r3, [sp]
1250: e1a02000 mov r2, r0
1254: ebfffffe bl 0 <mangled name>
1254: R_ARM_CALL _ZSt9__find_ifIN9__gnu_cxx17__normal_iterator
00000000 <mangled name>:
0: e16d42f0 strd r4, [sp, #-32]! ; 0xffffffe0
4: e1cd60f8 strd r6, [sp, #8]
8: e1cd81f0 strd r8, [sp, #16]
c: e58db018 str fp, [sp, #24]
10: e58de01c str lr, [sp, #28]
14: e28db01c add fp, sp, #28
18: e1a09002 mov r9, r2
1c: e1a07000 mov r7, r0
20: e0608002 rsb r8, r0, r2
24: e1a08348 asr r8, r8, #6
28: e30a3aab movw r3, #43691 ; 0xaaab
2c: e34a3aaa movt r3, #43690 ; 0xaaaa
, который предполагает, что R2 используется правильно!
Мои теории примерно такие:
- Компилятор правильно компилирует каждый файл, и что-то происходит на следующих этапах.
- На самом деле есть ошибка компилятора, которая не отображается выводом objdump в конкретном файле, содержащем функцию-обертку.
Даже addr2line показывает что-то вроде этого:
0x00001254: _ZSt9__find_ifIN9__gnu_cxx17__normal_iteratorIPKN2ue7VariantINS2_12_...
(inlined by) _ZSt7find_ifIN9__gnu_cxx17__normal_iteratorIPKN2ue7VariantINS2_12_...
(inlined by) find_if wrapper
(inlined by) LookUpEvalResultFun at ...
что говорит о том, что objdump не лжет; что-то поддерживает первую теорию.
У вас есть идеи?
Спасибо.