gq3 gq3 - 2 months ago 9
C++ Question

Assembly, global variable

I have the following source code:

const ClassTwo g_classTwo;

void ClassOne::first()
{
g_classTwo.doSomething(1);
}

void ClassOne::second()
{
g_classTwo.doSomething(2);
}


Which produces the following objdump:

void ClassOne::first()
{
1089c50: e1a0c00d mov ip, sp
1089c54: e92dd800 push {fp, ip, lr, pc}
1089c58: e24cb004 sub fp, ip, #4
1089c5c: e24dd008 sub sp, sp, #8
1089c60: e50b0010 str r0, [fp, #-16]
g_classTwo.doSomething(1);
1089c64: e59f3014 ldr r3, [pc, #20] ; 1089c80 <ClassOne::first()+0x30>
1089c68: e08f3003 add r3, pc, r3
1089c6c: e1a00003 mov r0, r3
1089c70: e3a01001 mov r1, #1
1089c74: ebffffe2 bl 1089c04 <ClassTwo::doSomething(int) const>
}
1089c78: e24bd00c sub sp, fp, #12
1089c7c: e89da800 ldm sp, {fp, sp, pc}
1089c80: 060cd35c .word 0x060cd35c

01089c84 <ClassOne::second()>:

void ClassOne::second()
{
1089c84: e1a0c00d mov ip, sp
1089c88: e92dd800 push {fp, ip, lr, pc}
1089c8c: e24cb004 sub fp, ip, #4
1089c90: e24dd008 sub sp, sp, #8
1089c94: e50b0010 str r0, [fp, #-16]
g_classTwo.doSomething(2);
1089c98: e59f3014 ldr r3, [pc, #20] ; 1089cb4 <ClassOne::second()+0x30>
1089c9c: e08f3003 add r3, pc, r3
1089ca0: e1a00003 mov r0, r3
1089ca4: e3a01002 mov r1, #2
1089ca8: ebffffd5 bl 1089c04 <ClassTwo::doSomething(int) const>
}
1089cac: e24bd00c sub sp, fp, #12
1089cb0: e89da800 ldm sp, {fp, sp, pc}
1089cb4: 060cd328 .word 0x060cd328


Both methods are loading the address of
g_classTwo
with a pc relative offset:
ldr r3, [pc, #20]
, which translates to
0x060cd35c
and
0x060cd328
for the first and second method respectively.

Why are the addresses different even though they are both addressing the same global variable?

How do those addresses relate to the nm output for the same symbol:
07156fcc b g_classTwo
?

Answer

In ClassOne::first() you have:

1089c64:   e59f3014    ldr r3, [pc, #20]   ; 1089c80 <ClassOne::first()+0x30>
1089c68:   e08f3003    add r3, pc, r3
1089c6c:   e1a00003    mov r0, r3
...
1089c80:   060cd35c    .word   0x060cd35c

In ClassOne::second() you have:

1089c98:   e59f3014    ldr r3, [pc, #20]   ; 1089cb4 <ClassOne::second()+0x30>
1089c9c:   e08f3003    add r3, pc, r3
1089ca0:   e1a00003    mov r0, r3
...
1089cb4:   060cd328    .word   0x060cd328

In both, r0 is the this pointer (g_classTwo). As you can see, after loading an address from the literal pool into r3 it is summed to pc to get r0.

In ClassOne::first(), you get r0 = pc + r3 = 0x01089c70 + 0x060cd35c = 0x07156fcc.

In ClassOne::second(), you get r0 = pc + r3 = 0x01089ca4 + 0x060cd328 = 0x07156fcc.

So for both the this pointer is 0x07156fcc, which is the address of g_classTwo.

Comments