2014년 1월 29일 수요일

포인터와 배열은 어떻게 다른가 in assembly level

포인터와 배열은 다들 알다시피 비슷하지만 다른데, 어셈블리 레벨에서 보면 더욱 자세히 와닿을 수 있다.

다음은 간단하게 배열과 포인터를 각각 사용하는 c 코드와 그로부터 만들어진 어셈블리 코드이다.

#include <stdio.h>
char a[] = "abc";
int main(void)
{
printf("%p\n", a);
return 0;
}
view raw arr.c hosted with ❤ by GitHub
.file "arr.c"
.globl a
.data
.type a, @object
.size a, 4
a:
.string "abc"
.section .rodata
.LC0:
.string "%p\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $a, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3"
.section .note.GNU-stack,"",@progbits
view raw arr.s hosted with ❤ by GitHub
#include <stdio.h>
char *a = "abc";
int main(void)
{
printf("%p\n", a);
return 0;
}
view raw ptr.c hosted with ❤ by GitHub
.file "ptr.c"
.globl a
.section .rodata
.LC0:
.string "abc"
.data
.align 8
.type a, @object
.size a, 8
a:
.quad .LC0
.section .rodata
.LC1:
.string "%p\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq a(%rip), %rax
movq %rax, %rsi
movl $.LC1, %edi
movl $0, %eax
call printf
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3"
.section .note.GNU-stack,"",@progbits
view raw ptr.s hosted with ❤ by GitHub

arr.s의 6, 7라인. 그리고 22라인을 보자.
어레이의 경우는 리터럴의 시작주소가 곧 자신의 위치이다.
따라서 접근을 할 때, $a와 같이 해당 심볼의 위치를 바로 가져온다.

ptr.s에서는 4,5,10,11라인. 그리고 26라인을 보자.
반면, 포인터는 리터럴의 시작주소를 값으로 가진다.
따라서 접근 시, a(%rip)와 같이, rip relative 방식으로 해당 변수의 '값'을 가져온다.

댓글 없음:

댓글 쓰기