Мой фрагмент кода C принимает адрес аргумента и сохраняет его в энергозависимой памяти (предварительно обработанный код):
void foo(unsigned int x) {
*(volatile unsigned int*)(0x4000000 + 0xd4) = (unsigned int)(&x);
}
int main() {
foo(1);
while(1);
}
Я использовал SVN-версию GCC для компиляции этого кода. В конце функции foo
я ожидал бы, что в стеке будет храниться значение 1
, а при 0x40000d4
адрес будет указывать на это значение. Когда я компилирую без оптимизации, используя флаг -O0
, я получаю ожидаемый вывод сборки ARM7TMDI (закомментирован для вашего удобства):
.align 2
.global foo
.type foo, %function
foo:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 8
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
sub sp, sp, #8
str r0, [sp, #4] @ 3. Store the argument on the stack
mov r3, #67108864
add r3, r3, #212
add r2, sp, #4 @ 4. Address of the stack variable
str r2, [r3, #0] @ 5. Store the address at 0x40000d4
add sp, sp, #8
bx lr
.size foo, .-foo
.align 2
.global main
.type main, %function
main:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
stmfd sp!, {r4, lr}
mov r0, #1 @ 1. Pass the argument in register 0
bl foo @ 2. Call function foo
.L4:
b .L4
.size main, .-main
.ident "GCC: (GNU) 4.4.0 20080820 (experimental)"
Он явно сохраняет аргумент сначала в стеке, а оттуда сохраняет его в 0x40000d4
. Когда я компилирую с оптимизацией, используя -O1
, я получаю нечто неожиданное:
.align 2
.global foo
.type foo, %function
foo:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 8
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
sub sp, sp, #8
mov r2, #67108864
add r3, sp, #4 @ 3. Address of *something* on the stack
str r3, [r2, #212] @ 4. Store the address at 0x40000d4
add sp, sp, #8
bx lr
.size foo, .-foo
.align 2
.global main
.type main, %function
main:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
stmfd sp!, {r4, lr}
mov r0, #1 @ 1. Pass the argument in register 0
bl foo @ 2. Call function foo
.L4:
b .L4
.size main, .-main
.ident "GCC: (GNU) 4.4.0 20080820 (experimental)"
На этот раз аргумент никогда не сохраняется в стеке, даже если что-то из стека все еще хранится в 0x40000d4
.
Это просто ожидаемое / неопределенное поведение? Я сделал что-то не так или действительно нашел ошибку компилятора & trade;?