/*
 * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

#ifndef _MACHO_X86_64_RELOC_H_
#define _MACHO_X86_64_RELOC_H_

/*
 * Relocations for x86_64 are a bit different than for other architectures in
 * Mach-O: Scattered relocations are not used.  Almost all relocations produced
 * by the compiler are external relocations.  An external relocation has the
 * r_extern bit set to 1 and the r_symbolnum field contains the symbol table
 * index of the target label.
 * 
 * When the assembler is generating relocations, if the target label is a local
 * label (begins with 'L'), then the previous non-local label in the same
 * section is used as the target of the external relocation.  An addend is used
 * with the distance from that non-local label to the target label.  Only when
 * there is no previous non-local label in the section is an internal
 * relocation used.
 * 
 * The addend (i.e. the 4 in _foo+4) is encoded in the instruction (Mach-O does
 * not have RELA relocations).  For PC-relative relocations, the addend is
 * stored directly in the instruction.  This is different from other Mach-O
 * architectures, which encode the addend minus the current section offset.
 * 
 * The relocation types are:
 * 
 * 	X86_64_RELOC_UNSIGNED	// for absolute addresses
 * 	X86_64_RELOC_SIGNED		// for signed 32-bit displacement
 * 	X86_64_RELOC_BRANCH		// a CALL/JMP instruction with 32-bit displacement
 * 	X86_64_RELOC_GOT_LOAD	// a MOVQ load of a GOT entry
 * 	X86_64_RELOC_GOT		// other GOT references
 * 	X86_64_RELOC_SUBTRACTOR	// must be followed by a X86_64_RELOC_UNSIGNED
 * 
 * The following are sample assembly instructions, followed by the relocation
 * and section content they generate in an object file:
 * 
 * 	call _foo
 * 		r_type=X86_64_RELOC_BRANCH, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
 * 		E8 00 00 00 00
 * 
 * 	call _foo+4
 * 		r_type=X86_64_RELOC_BRANCH, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
 * 		E8 04 00 00 00 
 * 
 * 	movq _foo@GOTPCREL(%rip), %rax
 * 		r_type=X86_64_RELOC_GOT_LOAD, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
 * 		48 8B 05 00 00 00 00
 * 	
 * 	pushq _foo@GOTPCREL(%rip)
 * 		r_type=X86_64_RELOC_GOT, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
 * 		FF 35 00 00 00 00
 * 	
 * 	movl _foo(%rip), %eax
 * 		r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
 * 		8B 05 00 00 00 00
 * 
 * 	movl _foo+4(%rip), %eax
 * 		r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
 * 		8B 05 04 00 00 00
 * 
 * 	movb  $0x12, _foo(%rip)
 * 		r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
 * 		C6 05 FF FF FF FF 12
 * 
 * 	movl  $0x12345678, _foo(%rip)
 * 		r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
 * 		C7 05 FC FF FF FF 78 56 34 12
 * 
 * 	.quad _foo
 * 		r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
 * 		00 00 00 00 00 00 00 00
 * 
 * 	.quad _foo+4
 * 		r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
 * 		04 00 00 00 00 00 00 00
 * 
 * 	.quad _foo - _bar
 * 		r_type=X86_64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_bar
 * 		r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
 * 		00 00 00 00 00 00 00 00
 * 
 * 	.quad _foo - _bar + 4
 * 		r_type=X86_64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_bar
 * 		r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
 * 		04 00 00 00 00 00 00 00
 * 	
 * 	.long _foo - _bar
 * 		r_type=X86_64_RELOC_SUBTRACTOR, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_bar
 * 		r_type=X86_64_RELOC_UNSIGNED, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_foo
 * 		00 00 00 00
 * 
 * 	lea L1(%rip), %rax
 * 		r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_prev
 * 		48 8d 05 12 00 00 00
 * 		// assumes _prev is the first non-local label 0x12 bytes before L1
 * 
 * 	lea L0(%rip), %rax
 * 		r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=0, r_pcrel=1, r_symbolnum=3
 * 		48 8d 05 56 00 00 00
 *		// assumes L0 is in third section and there is no previous non-local label.
 *		// The rip-relative-offset of 0x00000056 is L0-address_of_next_instruction.
 *		// address_of_next_instruction is the address of the relocation + 4.
 *
 *     add     $6,L0(%rip)
 *             r_type=X86_64_RELOC_SIGNED_1, r_length=2, r_extern=0, r_pcrel=1, r_symbolnum=3
 *		83 05 18 00 00 00 06
 *		// assumes L0 is in third section and there is no previous non-local label.
 *		// The rip-relative-offset of 0x00000018 is L0-address_of_next_instruction.
 *		// address_of_next_instruction is the address of the relocation + 4 + 1.
 *		// The +1 comes from SIGNED_1.  This is used because the relocation is not
 *		// at the end of the instruction.
 *
 * 	.quad L1
 * 		r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_prev
 * 		12 00 00 00 00 00 00 00
 * 		// assumes _prev is the first non-local label 0x12 bytes before L1
 * 
 * 	.quad L0
 * 		r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=0, r_pcrel=0, r_symbolnum=3
 * 		56 00 00 00 00 00 00 00
 * 		// assumes L0 is in third section, has an address of 0x00000056 in .o
 * 		// file, and there is no previous non-local label
 * 
 * 	.quad _foo - .
 * 		r_type=X86_64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_prev
 * 		r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
 * 		EE FF FF FF FF FF FF FF
 * 		// assumes _prev is the first non-local label 0x12 bytes before this
 * 		// .quad
 * 
 * 	.quad _foo - L1
 * 		r_type=X86_64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_prev
 * 		r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
 * 		EE FF FF FF FF FF FF FF
 * 		// assumes _prev is the first non-local label 0x12 bytes before L1
 * 
 * 	.quad L1 - _prev
 * 		// No relocations.  This is an assembly time constant.
 * 		12 00 00 00 00 00 00 00
 * 		// assumes _prev is the first non-local label 0x12 bytes before L1
 *
 *
 *
 * In final linked images, there are only two valid relocation kinds:
 *
 *     r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_pcrel=0, r_extern=1, r_symbolnum=sym_index
 *	This tells dyld to add the address of a symbol to a pointer sized (8-byte)
 *  piece of data (i.e on disk the 8-byte piece of data contains the addend). The 
 *  r_symbolnum contains the index into the symbol table of the target symbol.
 *
 *     r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_pcrel=0, r_extern=0, r_symbolnum=0
 * This tells dyld to adjust the pointer sized (8-byte) piece of data by the amount
 * the containing image was loaded from its base address (e.g. slide).
 *
 */ 
enum reloc_type_x86_64
{
	X86_64_RELOC_UNSIGNED,		// for absolute addresses
	X86_64_RELOC_SIGNED,		// for signed 32-bit displacement
	X86_64_RELOC_BRANCH,		// a CALL/JMP instruction with 32-bit displacement
	X86_64_RELOC_GOT_LOAD,		// a MOVQ load of a GOT entry
	X86_64_RELOC_GOT,			// other GOT references
	X86_64_RELOC_SUBTRACTOR,	// must be followed by a X86_64_RELOC_UNSIGNED
	X86_64_RELOC_SIGNED_1,		// for signed 32-bit displacement with a -1 addend
	X86_64_RELOC_SIGNED_2,		// for signed 32-bit displacement with a -2 addend
	X86_64_RELOC_SIGNED_4,		// for signed 32-bit displacement with a -4 addend
	X86_64_RELOC_TLV,		// for thread local variables
};

#endif /* #ifndef _MACHO_X86_64_RELOC_H_ */
