I think Even T. has the answer. You passed in a variable, you cannot take the address of that variable inside the function, you can take the address of a copy of that variable though, btw that variable is typically a register so it doesnt have an address. Once you leave that function its all gone, the calling function loses it. If you need the address in the function you have to pass by reference not pass by value, send the address. It looks to me that the bug is in your code, not gcc.
BTW, using *(volatile blah *)0xabcd or any other method to try to program registers is going to bite you eventually. gcc and most other compilers have this uncanny way of knowing exactly the worst time to strike.
Say the day you change from this
*(volatile unsigned int *)0x12345 = someuintvariable;
to
*(volatile unsigned int *)0x12345 = 0x12;
A good compiler will realize that you are only storing 8 bits and there is no reason to waste a 32 bit store for that, depending on the architecture you specified, or the default architecture for that compiler that day, so it is within its rights to optimize that to an strb instead of an str.
After having been burned by gcc and others with this dozens of times I have resorted to forcing the issue:
.globl PUT32
PUT32:
str r1,[r0]
bx lr
PUT32(0x12345,0x12);
Costs a few extra clock cycles but my code continues to work yesterday, today, and will work tomorrow with any optimization flag. Not having to re-visit old code and sleeping peacefully through the night is worth a few extra clock cycles here and there.
Also if your code breaks when you compile for release instead of compile for debug, that also means it is most likely a bug in your code.