IA-32e Mode RIP Relative Addressing.
비교를 위하여
1. absolute addressing
01 .text
02 .global _start
03
04 _start:
05 mov $0xd, %rdx
06
07 mov $msg, %rsi
08 pushq $0x1
09 pop %rax
10 mov %rax, %rdi
11 syscall
12
13 xor %rdi, %rdi
14 pushq $0x3c
15 pop %rax
16 syscall
17
18 .data
19 msg:
20 .ascii "Hello world!n"
=============================================================================
2. RIP Relative addressing.
01 .text
02 .global _start
03
04 _start:
05 mov $0xd, %rdx
06
07 leaq msg(%rip), %rsi
08 pushq $0x1
09 pop %rax
10 mov %rax, %rdi
11 syscall
12
13 xor %rdi, %rdi
14 pushq $0x3c
15 pop %rax
16 syscall
17
18 msg:
19 .ascii "Hello world!n"
=============================================================================
2개의 프로그램은 동일한 기능을 합니다.
차이가 나는 곳은 7 line인데 absolute addressing의 경우는 대상 data가 .data section에 존재합니다.
absolute addressing 예제 18 line에서 .data section 지정함.
그러나 RIP Relative addressing에서는 동일하게 .text section에서 대상 data를 RIP Relative addressing을
이용하여 data를 지정함(7 line).
정확한 분석을 위하여 해당 프로그램을 컴파일하여 objdump하면
objdump -d hello (컴파일 실행파일명을 hello)
0000000000400078 <.text>:
400078: 48 c7 c2 0d 00 00 00 mov $0xd,%rdx
40007f: 48 8d 35 10 00 00 00 lea 0x10(%rip),%rsi # 0x400096
400086: 6a 01 pushq $0x1
400088: 58 pop %rax
400089: 48 89 c7 mov %rax,%rdi
40008c: 0f 05 syscall
40008e: 48 31 ff xor %rdi,%rdi
400091: 6a 3c pushq $0x3c
400093: 58 pop %rax
400094: 0f 05 syscall
400096: 48 rex.W // 여기서부터 msg로 Hello Worldn
400097: 65 gs
400098: 6c insb (%dx),%es:(%rdi)
400099: 6c insb (%dx),%es:(%rdi)
40009a: 6f outsl %ds:(%rsi),(%dx)
40009b: 20 77 6f and %dh,0x6f(%rdi)
40009e: 72 6c jb 0x40010c
4000a0: 64 21 0a and %ecx,%fs:(%rdx)
7 line의 leaq msg(%rip), %rsi가 lea 0x10(%rip),%rsi로 변환됨을 알수 있다.
7 line 실행시 rip는 다음 실행번지인 0x400086가 들어있으며 msg가 0x10으로
변환되어 rsi에는 0x400086 + 0x10 = 0x400096가 저장된다.
여기서 중요한것은 msg가 0x10으로 변환된것인데 이값은 rip와 실제 data가
들어있는 어드레스의 차이값이 0x10이기 때문이다.
실제로 0x400096부터 Hello world!n가 들어있다.
즉 RIP Relative Addressing은 RIP와 지정할 어드레스까지의 옵셋으로 지정한다.
댓글 3
-
도영주
2013.10.17 10:53
-
도영주
2013.10.19 16:16
mov $0x1, symb은 문법상 다르고.
leaq rax, symb
mov $0x1, rax
이렇게 되어야 하는데요~~ㅎㅎㅎ -
시대유감
2013.10.18 17:05
http://www.x86-64.org/documentation/assembly.html
여기서 보면 심볼을 사용하지 않을 때는 다음과 같이 그대로 계산되는거 같습니다.
movl $0x1, 0x10 (%rip)
will store the value 0x1 10 bytes after the end of the instruction.
하지만 심볼을 사용하면 무조건 RIP relative하게 저장된다고 합니다.
movl $0x1, symb(%rip)
Will write 0x1 to the address of symbol "symb".
도영주씨 말씀대로 Assembler에서 rip와 심볼간의 offset을 계산하여 바꿔주는 것이 아닐까 생각됩니다.
근데... mov $0x1, symb 해도 저장되는거 아닌가요?
코드 사이즈를 줄이기 위해서 RIP relative addressing을 권한다고 하는데 잘 이해가 안되는군요..
.
http://www.agner.org/optimize/optimizing_assembly.pdf - 21 page
여기보시면 알겠지만, RIP-relative addressing을 사용하는데, GAS sysntax가 헷갈리게 되어있네요.
다른 어셈블러는 RIP relative addressing을 사용할 때, default로 되어있는경우에는 실제 변수의 위치만을
default가 아닌 경우에 (default rel ) 문장을 사용하고, 실제 변수의 위치만을 주는 데 비해,
GAS/Intel Syntax의 경우에는 [mem+rip] 형태의 문장을 사용합니다.
이 문장에서 rip 는 RIP-relative addressing을 사용하기 위해서 사용한 것으로 보이네요.
결국엔 (+rip)라는 부분을 없다고 보고, [mem]이라는 부분을 접근한다는 것만 알면 되는 것이었네요.
아마 Assembler에서 해당 부분을 mem - rip = offset to operand로
변경하여, 절대 주소를 넘겨주기 때문에 가능한 것으로 보여집니다.