Different memory addresses?

3

I'm working on windows 10 and codeblocks, and my question is because by doing this I have the memory position for example 0060FEFC

  

1st Code

#include <stdio.h>

int main(void){

   int arreglo[4];
   printf("%p\n",arreglo); //Direccion de memoria 0060FEFC
   printf("%p\n",&arreglo[1]);                  //0060FF00
   printf("%p\n",&arreglo[2]);                  //0060FF04
   printf("%p\n",&arreglo[3]);                  //0060FF08

   for(int i=0;i<4;i++){
       printf("%p arreglo[%d]\n",&arreglo[i],i); //Direccion de memoria 0060FEFC arreglo[0]
                                                                      //0060FF00 arreglo[1]
                                                                      //0060FF04 arreglo[2]
                                                                      //0060FF08 arreglo[3]


   }

   return 0;
}

But instead if I just put the printf you can see that it starts with 0060FF00

  

2nd Code

#include <stdio.h>

int main(void){  

    int arreglo[4];
    printf("%p\n",arreglo); //Direccion de memoria 0060FF00 
    printf("%p\n",&arreglo[1]);                  //0060FF04
    printf("%p\n",&arreglo[2]);                  //0060FF08
    printf("%p\n",&arreglo[3]);                  //0060FF0C

    return 0;
}

Start with 0060FEFC

  

3rd Code

#include <stdio.h>

int main(void){
    int arreglo[4];
    for(int i=0;i<4;i++){ ///Direccion de memoria     0060FEFC arreglo[0]
        printf("%p arreglo[%d]\n",&arreglo[i],i);   //0060FF00 arreglo[1]
                                                    //0060FF04 arreglo[2]
                                                    //0060FF08 arreglo[3]
   }

   return 0;
}
    
asked by Juan2005 06.04.2018 в 10:14
source

3 answers

5

The explanation is that even if those codes are practically the same for you, the resulting binary can be very different ... it is even highly probable that the memory positions that it gives change depending on whether you compile with or without optimizations

And what is the difference?

In your case the difference is in the variable i . I do not know what compiler and compilation options you use, as I say the result is dependent on the compiler and its options ... in fact, if we compare the codes 2 and 3 that are the simplest we can see many differences

Linux - Clang 6.0.0 - options: no optimizations

Code 2

main:                                   # @main
    push    rbp
    mov     rbp, rsp
    sub     rsp, 48
    movabs  rdi, offset .L.str
    lea     rsi, [rbp - 32]
    mov     dword ptr [rbp - 4], 0
    mov     al, 0
    call    printf
    movabs  rdi, offset .L.str
    lea     rsi, [rbp - 32]
    add     rsi, 4
    mov     dword ptr [rbp - 36], eax # 4-byte Spill
    mov     al, 0
    call    printf
    movabs  rdi, offset .L.str
    lea     rsi, [rbp - 32]
    add     rsi, 8
    mov     dword ptr [rbp - 40], eax # 4-byte Spill
    mov     al, 0
    call    printf
    movabs  rdi, offset .L.str
    lea     rsi, [rbp - 32]
    add     rsi, 12
    mov     dword ptr [rbp - 44], eax # 4-byte Spill
    mov     al, 0
    call    printf
    xor     ecx, ecx
    mov     dword ptr [rbp - 48], eax # 4-byte Spill
    mov     eax, ecx
    add     rsp, 48
    pop     rbp
    ret
.L.str:
    .asciz  "%p\n"

Code 3

main:                                   # @main
    push    rbp
    mov     rbp, rsp
    sub     rsp, 48
    mov     dword ptr [rbp - 4], 0
    mov     dword ptr [rbp - 36], 0
.LBB0_1:                                # =>This Inner Loop Header: Depth=1
    cmp     dword ptr [rbp - 36], 4
    jge     .LBB0_4
    movabs  rdi, offset .L.str
    lea     rax, [rbp - 32]
    movsxd  rcx, dword ptr [rbp - 36]
    shl     rcx, 2
    add     rax, rcx
    mov     edx, dword ptr [rbp - 36]
    mov     rsi, rax
    mov     al, 0
    call    printf
    mov     dword ptr [rbp - 40], eax # 4-byte Spill
    mov     eax, dword ptr [rbp - 36]
    add     eax, 1
    mov     dword ptr [rbp - 36], eax
    jmp     .LBB0_1
.LBB0_4:
    xor     eax, eax
    add     rsp, 48
    pop     rbp
    ret
.L.str:
    .asciz  "%p arreglo[%d]\n"

Linux - Clang 6.0.0 - options: -O3

Code 2

main:                                   # @main
    sub     rsp, 24
    mov     rsi, rsp
    mov     edi, offset .L.str
    xor     eax, eax
    call    printf
    lea     rsi, [rsp + 4]
    mov     edi, offset .L.str
    xor     eax, eax
    call    printf
    lea     rsi, [rsp + 8]
    mov     edi, offset .L.str
    xor     eax, eax
    call    printf
    lea     rsi, [rsp + 12]
    mov     edi, offset .L.str
    xor     eax, eax
    call    printf
    xor     eax, eax
    add     rsp, 24
    ret
.L.str:
    .asciz  "%p\n"

Code 3

main:                                   # @main
    sub     rsp, 24
    mov     rsi, rsp
    mov     edi, offset .L.str
    xor     edx, edx
    xor     eax, eax
    call    printf
    lea     rsi, [rsp + 4]
    mov     edi, offset .L.str
    mov     edx, 1
    xor     eax, eax
    call    printf
    lea     rsi, [rsp + 8]
    mov     edi, offset .L.str
    mov     edx, 2
    xor     eax, eax
    call    printf
    lea     rsi, [rsp + 12]
    mov     edi, offset .L.str
    mov     edx, 3
    xor     eax, eax
    call    printf
    xor     eax, eax
    add     rsp, 24
    ret
.L.str:
    .asciz  "%p arreglo[%d]\n"

Notice that once the optimizations have been applied, the two binaries are practically the same ... whereas without optimizations they seem to be very little ... and different results will be obtained when changing the compiler ... for example, if we compile the two examples scon gcc 4.4.7 we get:

without optimizations

Code 2

.LC0:
    .string "%p\n"
main:
    push    rbp
    mov     rbp, rsp
    sub     rsp, 16
    lea     rax, [rbp-16]
    mov     rsi, rax
    mov     edi, OFFSET FLAT:.LC0
    mov     eax, 0
    call    printf
    lea     rax, [rbp-16]
    add     rax, 4
    mov     rsi, rax
    mov     edi, OFFSET FLAT:.LC0
    mov     eax, 0
    call    printf
    lea     rax, [rbp-16]
    add     rax, 8
    mov     rsi, rax
    mov     edi, OFFSET FLAT:.LC0
    mov     eax, 0
    call    printf
    lea     rax, [rbp-16]
    add     rax, 12
    mov     rsi, rax
    mov     edi, OFFSET FLAT:.LC0
    mov     eax, 0
    call    printf
    mov     eax, 0
    leave
    ret

Code 3

.LC0:
    .string "%p arreglo[%d]\n"
main:
    push    rbp
    mov     rbp, rsp
    sub     rsp, 32
    mov     DWORD PTR [rbp-4], 0
    jmp     .L2
.L3:
    mov     edx, DWORD PTR [rbp-4]
    lea     rax, [rbp-32]
    movsx   rdx, edx
    sal     rdx, 2
    lea     rcx, [rax+rdx]
    mov     eax, DWORD PTR [rbp-4]
    mov     edx, eax
    mov     rsi, rcx
    mov     edi, OFFSET FLAT:.LC0
    mov     eax, 0
    call    printf
    add     DWORD PTR [rbp-4], 1
.L2:
    cmp     DWORD PTR [rbp-4], 3
    setle   al
    test    al, al
    jne     .L3
    mov     eax, 0
    leave
    ret

with optimizations

Code 2

.LC0:
    .string "%p\n"
main:
    push    rbx
    mov     edi, OFFSET FLAT:.LC0
    xor     eax, eax
    sub     rsp, 16
    mov     rsi, rsp
    call    printf
    lea     rsi, [rsp+4]
    mov     edi, OFFSET FLAT:.LC0
    xor     eax, eax
    call    printf
    lea     rsi, [rsp+8]
    mov     edi, OFFSET FLAT:.LC0
    xor     eax, eax
    call    printf
    lea     rsi, [rsp+12]
    mov     edi, OFFSET FLAT:.LC0
    xor     eax, eax
    call    printf
    xor     eax, eax
    add     rsp, 16
    pop     rbx
    ret

Code 3

.LC0:
    .string "%p arreglo[%d]\n"
main:
    push    rbx
    xor     edx, edx
    mov     edi, OFFSET FLAT:.LC0
    xor     eax, eax
    sub     rsp, 16
    mov     rsi, rsp
    call    printf
    lea     rsi, [rsp+4]
    mov     edx, 1
    mov     edi, OFFSET FLAT:.LC0
    xor     eax, eax
    call    printf
    lea     rsi, [rsp+8]
    mov     edx, 2
    mov     edi, OFFSET FLAT:.LC0
    xor     eax, eax
    call    printf
    lea     rsi, [rsp+12]
    mov     edx, 3
    mov     edi, OFFSET FLAT:.LC0
    xor     eax, eax
    call    printf
    xor     eax, eax
    add     rsp, 16
    pop     rbx
    ret

As you see, they seem rather little ... roughly if they have some details in common ... but the same are not equal.

Do not worry about those details since the exact position of an element seldom matters ... what's really important is that your pointers point to where they should ... the memory positions are random and that randomness grows as you increase the complexity of the program.

    
answered by 06.04.2018 / 11:17
source
5

In general, there is nothing to guarantee that in each program execution the same variable will occupy the same memory position. For example, even if you add input parameters, the memory position changes. Or maybe not. The fact is that, although you see that you always get the same value, you can not trust that it is like that.

But even assuming you can trust that you get the same value, the point is that the two programs you sample are different. And that the memory stores not only the data of the program, but also the own machine code of the program. That would be one of the possible reasons for the discrepancy.

    
answered by 06.04.2018 в 10:22
2

Although the previous answers are quite complete, I think that in this case a simple answer may be the solution:

The compiler usually places the instructions of the program in one position, and then the static memory. As 2nd has more instructions to translate (1st and 3rd are a loop with 1 instruction) its position in memory is slightly higher.

    
answered by 06.04.2018 в 11:27