gq3
gq3

Reputation: 859

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?

Upvotes: 1

Views: 912

Answers (1)

Andrea Biondo
Andrea Biondo

Reputation: 1686

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.

Upvotes: 2

Related Questions