1213274Srpaulo/* BFD back-end for AMD 64 COFF files. 2213274Srpaulo Copyright 2006, 2007 Free Software Foundation, Inc. 3213274Srpaulo 4213274Srpaulo This file is part of BFD, the Binary File Descriptor library. 5213274Srpaulo 6213274Srpaulo This program is free software; you can redistribute it and/or modify 7213274Srpaulo it under the terms of the GNU General Public License as published by 8213274Srpaulo the Free Software Foundation; either version 2 of the License, or 9213274Srpaulo (at your option) any later version. 10213274Srpaulo 11213274Srpaulo This program is distributed in the hope that it will be useful, 12213274Srpaulo but WITHOUT ANY WARRANTY; without even the implied warranty of 13213274Srpaulo MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14213274Srpaulo GNU General Public License for more details. 15213274Srpaulo 16213274Srpaulo You should have received a copy of the GNU General Public License 17213274Srpaulo along with this program; if not, write to the Free Software 18213274Srpaulo Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 19213274Srpaulo 20213274Srpaulo Written by Kai Tietz, OneVision Software GmbH&CoKg. */ 21213274Srpaulo 22213274Srpaulo#ifndef COFF_WITH_pex64 23213274Srpaulo#define COFF_WITH_pex64 24213274Srpaulo#endif 25213274Srpaulo 26213274Srpaulo#include "sysdep.h" 27213274Srpaulo#include "bfd.h" 28213274Srpaulo#include "libbfd.h" 29213274Srpaulo#include "coff/x86_64.h" 30213274Srpaulo#include "coff/internal.h" 31213274Srpaulo#include "coff/pe.h" 32213274Srpaulo#include "libcoff.h" 33213274Srpaulo#include "libiberty.h" 34213274Srpaulo 35213274Srpaulo#define BADMAG(x) AMD64BADMAG(x) 36213274Srpaulo 37213274Srpaulo#ifdef COFF_WITH_pex64 38213274Srpaulo# undef AOUTSZ 39213274Srpaulo# define AOUTSZ PEPAOUTSZ 40213274Srpaulo# define PEAOUTHDR PEPAOUTHDR 41213274Srpaulo#endif 42213274Srpaulo 43213274Srpaulo#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2) 44213274Srpaulo 45213274Srpaulo/* The page size is a guess based on ELF. */ 46213274Srpaulo 47213274Srpaulo#define COFF_PAGE_SIZE 0x1000 48213274Srpaulo 49213274Srpaulo/* For some reason when using AMD COFF the value stored in the .text 50213274Srpaulo section for a reference to a common symbol is the value itself plus 51213274Srpaulo any desired offset. Ian Taylor, Cygnus Support. */ 52213274Srpaulo 53213274Srpaulo/* If we are producing relocatable output, we need to do some 54213274Srpaulo adjustments to the object file that are not done by the 55213274Srpaulo bfd_perform_relocation function. This function is called by every 56213274Srpaulo reloc type to make any required adjustments. */ 57213274Srpaulo 58213274Srpaulostatic bfd_reloc_status_type 59213274Srpaulocoff_amd64_reloc (bfd *abfd, 60213274Srpaulo arelent *reloc_entry, 61213274Srpaulo asymbol *symbol, 62213274Srpaulo void * data, 63213274Srpaulo asection *input_section ATTRIBUTE_UNUSED, 64213274Srpaulo bfd *output_bfd, 65213274Srpaulo char **error_message ATTRIBUTE_UNUSED) 66213274Srpaulo{ 67213274Srpaulo symvalue diff; 68213274Srpaulo 69213274Srpaulo#if !defined(COFF_WITH_PE) 70213274Srpaulo if (output_bfd == NULL) 71213274Srpaulo return bfd_reloc_continue; 72213274Srpaulo#endif 73213274Srpaulo 74213274Srpaulo if (bfd_is_com_section (symbol->section)) 75213274Srpaulo { 76213274Srpaulo#if !defined(COFF_WITH_PE) 77213274Srpaulo /* We are relocating a common symbol. The current value in the 78213274Srpaulo object file is ORIG + OFFSET, where ORIG is the value of the 79213274Srpaulo common symbol as seen by the object file when it was compiled 80213274Srpaulo (this may be zero if the symbol was undefined) and OFFSET is 81213274Srpaulo the offset into the common symbol (normally zero, but may be 82213274Srpaulo non-zero when referring to a field in a common structure). 83213274Srpaulo ORIG is the negative of reloc_entry->addend, which is set by 84213274Srpaulo the CALC_ADDEND macro below. We want to replace the value in 85213274Srpaulo the object file with NEW + OFFSET, where NEW is the value of 86213274Srpaulo the common symbol which we are going to put in the final 87213274Srpaulo object file. NEW is symbol->value. */ 88213274Srpaulo diff = symbol->value + reloc_entry->addend; 89213274Srpaulo#else 90213274Srpaulo /* In PE mode, we do not offset the common symbol. */ 91213274Srpaulo diff = reloc_entry->addend; 92213274Srpaulo#endif 93213274Srpaulo } 94213274Srpaulo else 95213274Srpaulo { 96213274Srpaulo /* For some reason bfd_perform_relocation always effectively 97213274Srpaulo ignores the addend for a COFF target when producing 98213274Srpaulo relocatable output. This seems to be always wrong for 386 99213274Srpaulo COFF, so we handle the addend here instead. */ 100213274Srpaulo#if defined(COFF_WITH_PE) 101213274Srpaulo if (output_bfd == NULL) 102213274Srpaulo { 103213274Srpaulo reloc_howto_type *howto = reloc_entry->howto; 104213274Srpaulo 105213274Srpaulo /* Although PC relative relocations are very similar between 106213274Srpaulo PE and non-PE formats, but they are off by 1 << howto->size 107213274Srpaulo bytes. For the external relocation, PE is very different 108213274Srpaulo from others. See md_apply_fix3 () in gas/config/tc-amd64.c. 109213274Srpaulo When we link PE and non-PE object files together to 110213274Srpaulo generate a non-PE executable, we have to compensate it 111213274Srpaulo here. */ 112213274Srpaulo if(howto->pc_relative && howto->pcrel_offset) 113213274Srpaulo diff = -(1 << howto->size); 114213274Srpaulo else if(symbol->flags & BSF_WEAK) 115213274Srpaulo diff = reloc_entry->addend - symbol->value; 116213274Srpaulo else 117213274Srpaulo diff = -reloc_entry->addend; 118213274Srpaulo } 119213274Srpaulo else 120213274Srpaulo#endif 121213274Srpaulo diff = reloc_entry->addend; 122213274Srpaulo } 123213274Srpaulo 124213274Srpaulo#if defined(COFF_WITH_PE) 125213274Srpaulo /* FIXME: How should this case be handled? */ 126213274Srpaulo if (reloc_entry->howto->type == R_AMD64_IMAGEBASE 127213274Srpaulo && output_bfd != NULL 128213274Srpaulo && bfd_get_flavour (output_bfd) == bfd_target_coff_flavour) 129213274Srpaulo diff -= pe_data (output_bfd)->pe_opthdr.ImageBase; 130213274Srpaulo#endif 131213274Srpaulo 132213274Srpaulo#define DOIT(x) \ 133213274Srpaulo x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask)) 134213274Srpaulo 135213274Srpaulo if (diff != 0) 136213274Srpaulo { 137213274Srpaulo reloc_howto_type *howto = reloc_entry->howto; 138213274Srpaulo unsigned char *addr = (unsigned char *) data + reloc_entry->address; 139213274Srpaulo 140213274Srpaulo switch (howto->size) 141213274Srpaulo { 142213274Srpaulo case 0: 143213274Srpaulo { 144213274Srpaulo char x = bfd_get_8 (abfd, addr); 145213274Srpaulo DOIT (x); 146213274Srpaulo bfd_put_8 (abfd, x, addr); 147213274Srpaulo } 148213274Srpaulo break; 149213274Srpaulo 150213274Srpaulo case 1: 151213274Srpaulo { 152213274Srpaulo short x = bfd_get_16 (abfd, addr); 153213274Srpaulo DOIT (x); 154213274Srpaulo bfd_put_16 (abfd, (bfd_vma) x, addr); 155213274Srpaulo } 156213274Srpaulo break; 157213274Srpaulo 158213274Srpaulo case 2: 159213274Srpaulo { 160213274Srpaulo long x = bfd_get_32 (abfd, addr); 161213274Srpaulo DOIT (x); 162213274Srpaulo bfd_put_32 (abfd, (bfd_vma) x, addr); 163213274Srpaulo } 164213274Srpaulo break; 165213274Srpaulo case 4: 166213274Srpaulo { 167213274Srpaulo long long x = bfd_get_64 (abfd, addr); 168213274Srpaulo DOIT (x); 169213274Srpaulo bfd_put_64 (abfd, (bfd_vma) x, addr); 170213274Srpaulo } 171213274Srpaulo break; 172213274Srpaulo 173213274Srpaulo default: 174213274Srpaulo abort (); 175213274Srpaulo } 176213274Srpaulo } 177213274Srpaulo 178213274Srpaulo /* Now let bfd_perform_relocation finish everything up. */ 179213274Srpaulo return bfd_reloc_continue; 180213274Srpaulo} 181213274Srpaulo 182213274Srpaulo#if defined(COFF_WITH_PE) 183213274Srpaulo/* Return TRUE if this relocation should appear in the output .reloc 184213274Srpaulo section. */ 185213274Srpaulo 186213274Srpaulostatic bfd_boolean 187213274Srpauloin_reloc_p (bfd *abfd ATTRIBUTE_UNUSED, reloc_howto_type *howto) 188213274Srpaulo{ 189213274Srpaulo return ! howto->pc_relative && howto->type != R_AMD64_IMAGEBASE; 190213274Srpaulo} 191213274Srpaulo#endif /* COFF_WITH_PE */ 192213274Srpaulo 193213274Srpaulo#ifndef PCRELOFFSET 194213274Srpaulo#define PCRELOFFSET TRUE 195213274Srpaulo#endif 196213274Srpaulo 197213274Srpaulostatic reloc_howto_type howto_table[] = 198213274Srpaulo{ 199213274Srpaulo EMPTY_HOWTO (0), 200213274Srpaulo HOWTO (R_AMD64_DIR64, /* type 1*/ 201213274Srpaulo 0, /* rightshift */ 202213274Srpaulo 4, /* size (0 = byte, 1 = short, 2 = long, 4 = long long) */ 203213274Srpaulo 64, /* bitsize */ 204213274Srpaulo FALSE, /* pc_relative */ 205213274Srpaulo 0, /* bitpos */ 206213274Srpaulo complain_overflow_bitfield, /* complain_on_overflow */ 207213274Srpaulo coff_amd64_reloc, /* special_function */ 208213274Srpaulo "R_X86_64_64", /* name */ 209213274Srpaulo TRUE, /* partial_inplace */ 210213274Srpaulo 0xffffffffffffffffll, /* src_mask */ 211213274Srpaulo 0xffffffffffffffffll, /* dst_mask */ 212213274Srpaulo TRUE), /* pcrel_offset */ 213213274Srpaulo HOWTO (R_AMD64_DIR32, /* type 2 */ 214213274Srpaulo 0, /* rightshift */ 215213274Srpaulo 2, /* size (0 = byte, 1 = short, 2 = long) */ 216213274Srpaulo 32, /* bitsize */ 217213274Srpaulo FALSE, /* pc_relative */ 218213274Srpaulo 0, /* bitpos */ 219213274Srpaulo complain_overflow_bitfield, /* complain_on_overflow */ 220213274Srpaulo coff_amd64_reloc, /* special_function */ 221213274Srpaulo "R_X86_64_32", /* name */ 222213274Srpaulo TRUE, /* partial_inplace */ 223213274Srpaulo 0xffffffff, /* src_mask */ 224213274Srpaulo 0xffffffff, /* dst_mask */ 225213274Srpaulo TRUE), /* pcrel_offset */ 226213274Srpaulo /* PE IMAGE_REL_AMD64_ADDR32NB relocation (3). */ 227213274Srpaulo HOWTO (R_AMD64_IMAGEBASE, /* type */ 228213274Srpaulo 0, /* rightshift */ 229213274Srpaulo 2, /* size (0 = byte, 1 = short, 2 = long) */ 230213274Srpaulo 32, /* bitsize */ 231213274Srpaulo FALSE, /* pc_relative */ 232213274Srpaulo 0, /* bitpos */ 233213274Srpaulo complain_overflow_bitfield, /* complain_on_overflow */ 234213274Srpaulo coff_amd64_reloc, /* special_function */ 235213274Srpaulo "rva32", /* name */ 236213274Srpaulo TRUE, /* partial_inplace */ 237213274Srpaulo 0xffffffff, /* src_mask */ 238213274Srpaulo 0xffffffff, /* dst_mask */ 239213274Srpaulo FALSE), /* pcrel_offset */ 240213274Srpaulo /* 32-bit longword PC relative relocation (4). */ 241213274Srpaulo HOWTO (R_AMD64_PCRLONG, /* type 4 */ 242213274Srpaulo 0, /* rightshift */ 243213274Srpaulo 2, /* size (0 = byte, 1 = short, 2 = long) */ 244213274Srpaulo 32, /* bitsize */ 245213274Srpaulo TRUE, /* pc_relative */ 246213274Srpaulo 0, /* bitpos */ 247213274Srpaulo complain_overflow_signed, /* complain_on_overflow */ 248213274Srpaulo coff_amd64_reloc, /* special_function */ 249213274Srpaulo "R_X86_64_PC32", /* name */ 250213274Srpaulo TRUE, /* partial_inplace */ 251213274Srpaulo 0xffffffff, /* src_mask */ 252213274Srpaulo 0xffffffff, /* dst_mask */ 253213274Srpaulo PCRELOFFSET), /* pcrel_offset */ 254213274Srpaulo 255213274Srpaulo HOWTO (R_AMD64_PCRLONG_1, /* type 5 */ 256213274Srpaulo 0, /* rightshift */ 257213274Srpaulo 2, /* size (0 = byte, 1 = short, 2 = long) */ 258213274Srpaulo 32, /* bitsize */ 259213274Srpaulo TRUE, /* pc_relative */ 260213274Srpaulo 0, /* bitpos */ 261213274Srpaulo complain_overflow_signed, /* complain_on_overflow */ 262213274Srpaulo coff_amd64_reloc, /* special_function */ 263213274Srpaulo "DISP32+1", /* name */ 264213274Srpaulo TRUE, /* partial_inplace */ 265213274Srpaulo 0xffffffff, /* src_mask */ 266213274Srpaulo 0xffffffff, /* dst_mask */ 267213274Srpaulo PCRELOFFSET), /* pcrel_offset */ 268213274Srpaulo HOWTO (R_AMD64_PCRLONG_2, /* type 6 */ 269213274Srpaulo 0, /* rightshift */ 270213274Srpaulo 2, /* size (0 = byte, 1 = short, 2 = long) */ 271213274Srpaulo 32, /* bitsize */ 272213274Srpaulo TRUE, /* pc_relative */ 273213274Srpaulo 0, /* bitpos */ 274213274Srpaulo complain_overflow_signed, /* complain_on_overflow */ 275213274Srpaulo coff_amd64_reloc, /* special_function */ 276213274Srpaulo "DISP32+2", /* name */ 277213274Srpaulo TRUE, /* partial_inplace */ 278213274Srpaulo 0xffffffff, /* src_mask */ 279213274Srpaulo 0xffffffff, /* dst_mask */ 280213274Srpaulo PCRELOFFSET), /* pcrel_offset */ 281213274Srpaulo HOWTO (R_AMD64_PCRLONG_3, /* type 7 */ 282213274Srpaulo 0, /* rightshift */ 283213274Srpaulo 2, /* size (0 = byte, 1 = short, 2 = long) */ 284213274Srpaulo 32, /* bitsize */ 285213274Srpaulo TRUE, /* pc_relative */ 286213274Srpaulo 0, /* bitpos */ 287213274Srpaulo complain_overflow_signed, /* complain_on_overflow */ 288213274Srpaulo coff_amd64_reloc, /* special_function */ 289213274Srpaulo "DISP32+3", /* name */ 290213274Srpaulo TRUE, /* partial_inplace */ 291213274Srpaulo 0xffffffff, /* src_mask */ 292213274Srpaulo 0xffffffff, /* dst_mask */ 293213274Srpaulo PCRELOFFSET), /* pcrel_offset */ 294213274Srpaulo HOWTO (R_AMD64_PCRLONG_4, /* type 8 */ 295213274Srpaulo 0, /* rightshift */ 296213274Srpaulo 2, /* size (0 = byte, 1 = short, 2 = long) */ 297213274Srpaulo 32, /* bitsize */ 298213274Srpaulo TRUE, /* pc_relative */ 299213274Srpaulo 0, /* bitpos */ 300213274Srpaulo complain_overflow_signed, /* complain_on_overflow */ 301213274Srpaulo coff_amd64_reloc, /* special_function */ 302213274Srpaulo "DISP32+4", /* name */ 303213274Srpaulo TRUE, /* partial_inplace */ 304213274Srpaulo 0xffffffff, /* src_mask */ 305213274Srpaulo 0xffffffff, /* dst_mask */ 306213274Srpaulo PCRELOFFSET), /* pcrel_offset */ 307213274Srpaulo HOWTO (R_AMD64_PCRLONG_5, /* type 9 */ 308213274Srpaulo 0, /* rightshift */ 309213274Srpaulo 2, /* size (0 = byte, 1 = short, 2 = long) */ 310213274Srpaulo 32, /* bitsize */ 311213274Srpaulo TRUE, /* pc_relative */ 312213274Srpaulo 0, /* bitpos */ 313213274Srpaulo complain_overflow_signed, /* complain_on_overflow */ 314213274Srpaulo coff_amd64_reloc, /* special_function */ 315213274Srpaulo "DISP32+5", /* name */ 316213274Srpaulo TRUE, /* partial_inplace */ 317213274Srpaulo 0xffffffff, /* src_mask */ 318213274Srpaulo 0xffffffff, /* dst_mask */ 319213274Srpaulo PCRELOFFSET), /* pcrel_offset */ 320213274Srpaulo EMPTY_HOWTO (10), /* R_AMD64_SECTION 10 */ 321213274Srpaulo#if defined(COFF_WITH_PE) 322213274Srpaulo /* 32-bit longword section relative relocation (11). */ 323213274Srpaulo HOWTO (R_AMD64_SECREL, /* type */ 324213274Srpaulo 0, /* rightshift */ 325213274Srpaulo 2, /* size (0 = byte, 1 = short, 2 = long) */ 326213274Srpaulo 32, /* bitsize */ 327213274Srpaulo FALSE, /* pc_relative */ 328213274Srpaulo 0, /* bitpos */ 329213274Srpaulo complain_overflow_bitfield, /* complain_on_overflow */ 330213274Srpaulo coff_amd64_reloc, /* special_function */ 331213274Srpaulo "secrel32", /* name */ 332213274Srpaulo TRUE, /* partial_inplace */ 333213274Srpaulo 0xffffffff, /* src_mask */ 334213274Srpaulo 0xffffffff, /* dst_mask */ 335213274Srpaulo TRUE), /* pcrel_offset */ 336213274Srpaulo#else 337213274Srpaulo EMPTY_HOWTO (11), 338213274Srpaulo#endif 339213274Srpaulo EMPTY_HOWTO (12), 340213274Srpaulo EMPTY_HOWTO (13), 341213274Srpaulo#ifndef DONT_EXTEND_AMD64 342213274Srpaulo HOWTO (R_AMD64_PCRQUAD, 343213274Srpaulo 0, /* rightshift */ 344213274Srpaulo 4, /* size (0 = byte, 1 = short, 2 = long) */ 345213274Srpaulo 64, /* bitsize */ 346213274Srpaulo TRUE, /* pc_relative */ 347213274Srpaulo 0, /* bitpos */ 348213274Srpaulo complain_overflow_signed, /* complain_on_overflow */ 349213274Srpaulo coff_amd64_reloc, /* special_function */ 350213274Srpaulo "R_X86_64_PC64", /* name */ 351213274Srpaulo TRUE, /* partial_inplace */ 352213274Srpaulo 0xffffffffffffffffll, /* src_mask */ 353213274Srpaulo 0xffffffffffffffffll, /* dst_mask */ 354213274Srpaulo PCRELOFFSET), /* pcrel_offset */ 355213274Srpaulo#else 356213274Srpaulo EMPTY_HOWTO (14), 357213274Srpaulo#endif 358213274Srpaulo /* Byte relocation (15). */ 359213274Srpaulo HOWTO (R_RELBYTE, /* type */ 360213274Srpaulo 0, /* rightshift */ 361213274Srpaulo 0, /* size (0 = byte, 1 = short, 2 = long) */ 362213274Srpaulo 8, /* bitsize */ 363213274Srpaulo FALSE, /* pc_relative */ 364213274Srpaulo 0, /* bitpos */ 365213274Srpaulo complain_overflow_bitfield, /* complain_on_overflow */ 366213274Srpaulo coff_amd64_reloc, /* special_function */ 367213274Srpaulo "R_X86_64_8", /* name */ 368213274Srpaulo TRUE, /* partial_inplace */ 369213274Srpaulo 0x000000ff, /* src_mask */ 370213274Srpaulo 0x000000ff, /* dst_mask */ 371213274Srpaulo PCRELOFFSET), /* pcrel_offset */ 372213274Srpaulo /* 16-bit word relocation (16). */ 373213274Srpaulo HOWTO (R_RELWORD, /* type */ 374213274Srpaulo 0, /* rightshift */ 375213274Srpaulo 1, /* size (0 = byte, 1 = short, 2 = long) */ 376213274Srpaulo 16, /* bitsize */ 377213274Srpaulo FALSE, /* pc_relative */ 378213274Srpaulo 0, /* bitpos */ 379213274Srpaulo complain_overflow_bitfield, /* complain_on_overflow */ 380213274Srpaulo coff_amd64_reloc, /* special_function */ 381213274Srpaulo "R_X86_64_16", /* name */ 382213274Srpaulo TRUE, /* partial_inplace */ 383213274Srpaulo 0x0000ffff, /* src_mask */ 384213274Srpaulo 0x0000ffff, /* dst_mask */ 385213274Srpaulo PCRELOFFSET), /* pcrel_offset */ 386213274Srpaulo /* 32-bit longword relocation (17). */ 387213274Srpaulo HOWTO (R_RELLONG, /* type */ 388213274Srpaulo 0, /* rightshift */ 389213274Srpaulo 2, /* size (0 = byte, 1 = short, 2 = long) */ 390213274Srpaulo 32, /* bitsize */ 391213274Srpaulo FALSE, /* pc_relative */ 392213274Srpaulo 0, /* bitpos */ 393213274Srpaulo complain_overflow_bitfield, /* complain_on_overflow */ 394213274Srpaulo coff_amd64_reloc, /* special_function */ 395213274Srpaulo "R_X86_64_32S", /* name */ 396213274Srpaulo TRUE, /* partial_inplace */ 397213274Srpaulo 0xffffffff, /* src_mask */ 398213274Srpaulo 0xffffffff, /* dst_mask */ 399213274Srpaulo PCRELOFFSET), /* pcrel_offset */ 400213274Srpaulo /* Byte PC relative relocation (18). */ 401213274Srpaulo HOWTO (R_PCRBYTE, /* type */ 402213274Srpaulo 0, /* rightshift */ 403213274Srpaulo 0, /* size (0 = byte, 1 = short, 2 = long) */ 404213274Srpaulo 8, /* bitsize */ 405213274Srpaulo TRUE, /* pc_relative */ 406213274Srpaulo 0, /* bitpos */ 407213274Srpaulo complain_overflow_signed, /* complain_on_overflow */ 408213274Srpaulo coff_amd64_reloc, /* special_function */ 409213274Srpaulo "R_X86_64_PC8", /* name */ 410213274Srpaulo TRUE, /* partial_inplace */ 411213274Srpaulo 0x000000ff, /* src_mask */ 412213274Srpaulo 0x000000ff, /* dst_mask */ 413213274Srpaulo PCRELOFFSET), /* pcrel_offset */ 414213274Srpaulo /* 16-bit word PC relative relocation (19). */ 415213274Srpaulo HOWTO (R_PCRWORD, /* type */ 416213274Srpaulo 0, /* rightshift */ 417213274Srpaulo 1, /* size (0 = byte, 1 = short, 2 = long) */ 418213274Srpaulo 16, /* bitsize */ 419213274Srpaulo TRUE, /* pc_relative */ 420213274Srpaulo 0, /* bitpos */ 421213274Srpaulo complain_overflow_signed, /* complain_on_overflow */ 422213274Srpaulo coff_amd64_reloc, /* special_function */ 423213274Srpaulo "R_X86_64_PC16", /* name */ 424213274Srpaulo TRUE, /* partial_inplace */ 425213274Srpaulo 0x0000ffff, /* src_mask */ 426213274Srpaulo 0x0000ffff, /* dst_mask */ 427213274Srpaulo PCRELOFFSET), /* pcrel_offset */ 428213274Srpaulo /* 32-bit longword PC relative relocation (20). */ 429213274Srpaulo HOWTO (R_PCRLONG, /* type */ 430213274Srpaulo 0, /* rightshift */ 431213274Srpaulo 2, /* size (0 = byte, 1 = short, 2 = long) */ 432213274Srpaulo 32, /* bitsize */ 433213274Srpaulo TRUE, /* pc_relative */ 434213274Srpaulo 0, /* bitpos */ 435213274Srpaulo complain_overflow_signed, /* complain_on_overflow */ 436213274Srpaulo coff_amd64_reloc, /* special_function */ 437213274Srpaulo "R_X86_64_PC32", /* name */ 438213274Srpaulo TRUE, /* partial_inplace */ 439213274Srpaulo 0xffffffff, /* src_mask */ 440213274Srpaulo 0xffffffff, /* dst_mask */ 441213274Srpaulo PCRELOFFSET) /* pcrel_offset */ 442213274Srpaulo}; 443213274Srpaulo 444213274Srpaulo/* Turn a howto into a reloc nunmber */ 445213274Srpaulo 446213274Srpaulo#define SELECT_RELOC(x,howto) { x.r_type = howto->type; } 447213274Srpaulo#define I386 1 /* Customize coffcode.h */ 448213274Srpaulo#define AMD64 1 449213274Srpaulo 450213274Srpaulo#define RTYPE2HOWTO(cache_ptr, dst) \ 451213274Srpaulo ((cache_ptr)->howto = \ 452213274Srpaulo ((dst)->r_type < ARRAY_SIZE (howto_table)) \ 453213274Srpaulo ? howto_table + (dst)->r_type \ 454213274Srpaulo : NULL) 455213274Srpaulo 456213274Srpaulo/* For 386 COFF a STYP_NOLOAD | STYP_BSS section is part of a shared 457213274Srpaulo library. On some other COFF targets STYP_BSS is normally 458213274Srpaulo STYP_NOLOAD. */ 459213274Srpaulo#define BSS_NOLOAD_IS_SHARED_LIBRARY 460213274Srpaulo 461213274Srpaulo/* Compute the addend of a reloc. If the reloc is to a common symbol, 462213274Srpaulo the object file contains the value of the common symbol. By the 463213274Srpaulo time this is called, the linker may be using a different symbol 464213274Srpaulo from a different object file with a different value. Therefore, we 465213274Srpaulo hack wildly to locate the original symbol from this file so that we 466213274Srpaulo can make the correct adjustment. This macro sets coffsym to the 467213274Srpaulo symbol from the original file, and uses it to set the addend value 468213274Srpaulo correctly. If this is not a common symbol, the usual addend 469213274Srpaulo calculation is done, except that an additional tweak is needed for 470213274Srpaulo PC relative relocs. 471213274Srpaulo FIXME: This macro refers to symbols and asect; these are from the 472213274Srpaulo calling function, not the macro arguments. */ 473213274Srpaulo 474213274Srpaulo#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ 475213274Srpaulo { \ 476213274Srpaulo coff_symbol_type *coffsym = NULL; \ 477213274Srpaulo \ 478213274Srpaulo if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ 479213274Srpaulo coffsym = (obj_symbols (abfd) \ 480213274Srpaulo + (cache_ptr->sym_ptr_ptr - symbols)); \ 481213274Srpaulo else if (ptr) \ 482213274Srpaulo coffsym = coff_symbol_from (abfd, ptr); \ 483213274Srpaulo \ 484213274Srpaulo if (coffsym != NULL \ 485213274Srpaulo && coffsym->native->u.syment.n_scnum == 0) \ 486213274Srpaulo cache_ptr->addend = - coffsym->native->u.syment.n_value; \ 487213274Srpaulo else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ 488213274Srpaulo && ptr->section != NULL) \ 489213274Srpaulo cache_ptr->addend = - (ptr->section->vma + ptr->value); \ 490213274Srpaulo else \ 491213274Srpaulo cache_ptr->addend = 0; \ 492213274Srpaulo if (ptr && howto_table[reloc.r_type].pc_relative) \ 493213274Srpaulo cache_ptr->addend += asect->vma; \ 494213274Srpaulo } 495213274Srpaulo 496213274Srpaulo/* We use the special COFF backend linker. For normal AMD64 COFF, we 497213274Srpaulo can use the generic relocate_section routine. For PE, we need our 498213274Srpaulo own routine. */ 499213274Srpaulo 500213274Srpaulo#if !defined(COFF_WITH_PE) 501213274Srpaulo 502213274Srpaulo#define coff_relocate_section _bfd_coff_generic_relocate_section 503213274Srpaulo 504213274Srpaulo#else /* COFF_WITH_PE */ 505213274Srpaulo 506213274Srpaulo/* The PE relocate section routine. The only difference between this 507213274Srpaulo and the regular routine is that we don't want to do anything for a 508213274Srpaulo relocatable link. */ 509213274Srpaulo 510213274Srpaulostatic bfd_boolean 511213274Srpaulocoff_pe_amd64_relocate_section (bfd *output_bfd, 512213274Srpaulo struct bfd_link_info *info, 513213274Srpaulo bfd *input_bfd, 514213274Srpaulo asection *input_section, 515213274Srpaulo bfd_byte *contents, 516213274Srpaulo struct internal_reloc *relocs, 517213274Srpaulo struct internal_syment *syms, 518213274Srpaulo asection **sections) 519213274Srpaulo{ 520213274Srpaulo if (info->relocatable) 521213274Srpaulo return TRUE; 522213274Srpaulo 523213274Srpaulo return _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,input_section, contents,relocs, syms, sections); 524213274Srpaulo} 525213274Srpaulo 526213274Srpaulo#define coff_relocate_section coff_pe_amd64_relocate_section 527213274Srpaulo 528213274Srpaulo#endif /* COFF_WITH_PE */ 529213274Srpaulo 530213274Srpaulo/* Convert an rtype to howto for the COFF backend linker. */ 531213274Srpaulo 532213274Srpaulostatic reloc_howto_type * 533213274Srpaulocoff_amd64_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED, 534213274Srpaulo asection *sec, 535213274Srpaulo struct internal_reloc *rel, 536213274Srpaulo struct coff_link_hash_entry *h, 537213274Srpaulo struct internal_syment *sym, 538213274Srpaulo bfd_vma *addendp) 539213274Srpaulo{ 540213274Srpaulo reloc_howto_type *howto; 541213274Srpaulo 542213274Srpaulo if (rel->r_type > ARRAY_SIZE (howto_table)) 543213274Srpaulo { 544213274Srpaulo bfd_set_error (bfd_error_bad_value); 545213274Srpaulo return NULL; 546213274Srpaulo } 547213274Srpaulo if (rel->r_type >= R_AMD64_PCRLONG_1 && rel->r_type <= R_AMD64_PCRLONG_5) 548213274Srpaulo { 549213274Srpaulo rel->r_vaddr += (bfd_vma)(rel->r_type-R_AMD64_PCRLONG); 550213274Srpaulo rel->r_type = R_AMD64_PCRLONG; 551213274Srpaulo } 552213274Srpaulo howto = howto_table + rel->r_type; 553213274Srpaulo 554213274Srpaulo#if defined(COFF_WITH_PE) 555213274Srpaulo /* Cancel out code in _bfd_coff_generic_relocate_section. */ 556213274Srpaulo *addendp = 0; 557213274Srpaulo#endif 558213274Srpaulo 559213274Srpaulo if (howto->pc_relative) 560213274Srpaulo *addendp += sec->vma; 561213274Srpaulo 562213274Srpaulo if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0) 563213274Srpaulo { 564213274Srpaulo /* This is a common symbol. The section contents include the 565213274Srpaulo size (sym->n_value) as an addend. The relocate_section 566213274Srpaulo function will be adding in the final value of the symbol. We 567213274Srpaulo need to subtract out the current size in order to get the 568213274Srpaulo correct result. */ 569213274Srpaulo BFD_ASSERT (h != NULL); 570213274Srpaulo 571213274Srpaulo#if !defined(COFF_WITH_PE) 572213274Srpaulo /* I think we *do* want to bypass this. If we don't, I have 573213274Srpaulo seen some data parameters get the wrong relocation address. 574213274Srpaulo If I link two versions with and without this section bypassed 575213274Srpaulo and then do a binary comparison, the addresses which are 576213274Srpaulo different can be looked up in the map. The case in which 577213274Srpaulo this section has been bypassed has addresses which correspond 578213274Srpaulo to values I can find in the map. */ 579213274Srpaulo *addendp -= sym->n_value; 580213274Srpaulo#endif 581213274Srpaulo } 582213274Srpaulo 583213274Srpaulo#if !defined(COFF_WITH_PE) 584213274Srpaulo /* If the output symbol is common (in which case this must be a 585213274Srpaulo relocatable link), we need to add in the final size of the 586213274Srpaulo common symbol. */ 587213274Srpaulo if (h != NULL && h->root.type == bfd_link_hash_common) 588213274Srpaulo *addendp += h->root.u.c.size; 589213274Srpaulo#endif 590213274Srpaulo 591213274Srpaulo#if defined(COFF_WITH_PE) 592213274Srpaulo if (howto->pc_relative) 593213274Srpaulo { 594213274Srpaulo *addendp -= 4; 595213274Srpaulo 596213274Srpaulo /* If the symbol is defined, then the generic code is going to 597213274Srpaulo add back the symbol value in order to cancel out an 598213274Srpaulo adjustment it made to the addend. However, we set the addend 599213274Srpaulo to 0 at the start of this function. We need to adjust here, 600213274Srpaulo to avoid the adjustment the generic code will make. FIXME: 601213274Srpaulo This is getting a bit hackish. */ 602213274Srpaulo if (sym != NULL && sym->n_scnum != 0) 603213274Srpaulo *addendp -= sym->n_value; 604213274Srpaulo } 605213274Srpaulo 606213274Srpaulo if (rel->r_type == R_AMD64_IMAGEBASE 607213274Srpaulo && (bfd_get_flavour (sec->output_section->owner) == bfd_target_coff_flavour)) 608213274Srpaulo *addendp -= pe_data (sec->output_section->owner)->pe_opthdr.ImageBase; 609213274Srpaulo 610213274Srpaulo if (rel->r_type == R_AMD64_SECREL) 611213274Srpaulo { 612213274Srpaulo bfd_vma osect_vma; 613213274Srpaulo 614213274Srpaulo if (h && (h->type == bfd_link_hash_defined || h->type == bfd_link_hash_defweak)) 615213274Srpaulo osect_vma = h->root.u.def.section->output_section->vma; 616213274Srpaulo else 617213274Srpaulo { 618213274Srpaulo asection *sec; 619213274Srpaulo int i; 620213274Srpaulo 621213274Srpaulo /* Sigh, the only way to get the section to offset against 622213274Srpaulo is to find it the hard way. */ 623213274Srpaulo for (sec = abfd->sections, i = 1; i < sym->n_scnum; i++) 624213274Srpaulo sec = sec->next; 625213274Srpaulo 626213274Srpaulo osect_vma = sec->output_section->vma; 627213274Srpaulo } 628213274Srpaulo 629213274Srpaulo *addendp -= osect_vma; 630213274Srpaulo } 631213274Srpaulo#endif 632213274Srpaulo 633213274Srpaulo return howto; 634213274Srpaulo} 635213274Srpaulo 636213274Srpaulo#define coff_bfd_reloc_type_lookup coff_amd64_reloc_type_lookup 637218822Sdim#ifdef notyet 638213274Srpaulo#define coff_bfd_reloc_name_lookup coff_amd64_reloc_name_lookup 639218822Sdim#endif 640213274Srpaulo 641213274Srpaulostatic reloc_howto_type * 642213274Srpaulocoff_amd64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code) 643213274Srpaulo{ 644213274Srpaulo switch (code) 645213274Srpaulo { 646213274Srpaulo case BFD_RELOC_RVA: 647213274Srpaulo return howto_table + R_AMD64_IMAGEBASE; 648213274Srpaulo case BFD_RELOC_32: 649213274Srpaulo return howto_table + R_AMD64_DIR32; 650213274Srpaulo case BFD_RELOC_64: 651213274Srpaulo return howto_table + R_AMD64_DIR64; 652213274Srpaulo case BFD_RELOC_64_PCREL: 653213274Srpaulo#ifndef DONT_EXTEND_AMD64 654213274Srpaulo return howto_table + R_AMD64_PCRQUAD; 655213274Srpaulo#else 656213274Srpaulo /* Fall through. */ 657213274Srpaulo#endif 658213274Srpaulo case BFD_RELOC_32_PCREL: 659213274Srpaulo return howto_table + R_AMD64_PCRLONG; 660213274Srpaulo case BFD_RELOC_X86_64_32S: 661213274Srpaulo return howto_table + R_RELLONG; 662213274Srpaulo case BFD_RELOC_16: 663213274Srpaulo return howto_table + R_RELWORD; 664213274Srpaulo case BFD_RELOC_16_PCREL: 665213274Srpaulo return howto_table + R_PCRWORD; 666213274Srpaulo case BFD_RELOC_8: 667213274Srpaulo return howto_table + R_RELBYTE; 668213274Srpaulo case BFD_RELOC_8_PCREL: 669213274Srpaulo return howto_table + R_PCRBYTE; 670213274Srpaulo#ifdef notyet 671213274Srpaulo#if defined(COFF_WITH_PE) 672213274Srpaulo case BFD_RELOC_32_SECREL: 673213274Srpaulo return howto_table + R_AMD64_SECREL; 674213274Srpaulo#endif 675213274Srpaulo#endif 676213274Srpaulo default: 677213274Srpaulo BFD_FAIL (); 678213274Srpaulo return 0; 679213274Srpaulo } 680213274Srpaulo} 681213274Srpaulo 682218822Sdim#ifdef notyet 683213274Srpaulostatic reloc_howto_type * 684213274Srpaulocoff_amd64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, 685213274Srpaulo const char *r_name) 686213274Srpaulo{ 687213274Srpaulo unsigned int i; 688213274Srpaulo 689213274Srpaulo for (i = 0; i < sizeof (howto_table) / sizeof (howto_table[0]); i++) 690213274Srpaulo if (howto_table[i].name != NULL 691213274Srpaulo && strcasecmp (howto_table[i].name, r_name) == 0) 692213274Srpaulo return &howto_table[i]; 693213274Srpaulo 694213274Srpaulo return NULL; 695213274Srpaulo} 696218822Sdim#endif 697213274Srpaulo 698213274Srpaulo#define coff_rtype_to_howto coff_amd64_rtype_to_howto 699213274Srpaulo 700213274Srpaulo#ifdef TARGET_UNDERSCORE 701213274Srpaulo 702213274Srpaulo/* If amd64 gcc uses underscores for symbol names, then it does not use 703213274Srpaulo a leading dot for local labels, so if TARGET_UNDERSCORE is defined 704213274Srpaulo we treat all symbols starting with L as local. */ 705213274Srpaulo 706213274Srpaulostatic bfd_boolean 707213274Srpaulocoff_amd64_is_local_label_name (bfd *abfd, const char *name) 708213274Srpaulo{ 709213274Srpaulo if (name[0] == 'L') 710213274Srpaulo return TRUE; 711213274Srpaulo 712213274Srpaulo return _bfd_coff_is_local_label_name (abfd, name); 713213274Srpaulo} 714213274Srpaulo 715213274Srpaulo#define coff_bfd_is_local_label_name coff_amd64_is_local_label_name 716213274Srpaulo 717213274Srpaulo#endif /* TARGET_UNDERSCORE */ 718213274Srpaulo 719213274Srpaulo#include "coffcode.h" 720213274Srpaulo 721213274Srpaulo#ifdef PE 722213274Srpaulo#define amd64coff_object_p pe_bfd_object_p 723213274Srpaulo#else 724213274Srpaulo#define amd64coff_object_p coff_object_p 725213274Srpaulo#endif 726213274Srpaulo 727213274Srpauloconst bfd_target 728213274Srpaulo#ifdef TARGET_SYM 729213274Srpaulo TARGET_SYM = 730213274Srpaulo#else 731213274Srpaulo x86_64coff_vec = 732213274Srpaulo#endif 733213274Srpaulo{ 734213274Srpaulo#ifdef TARGET_NAME 735213274Srpaulo TARGET_NAME, 736213274Srpaulo#else 737213274Srpaulo "coff-x86-64", /* Name. */ 738213274Srpaulo#endif 739213274Srpaulo bfd_target_coff_flavour, 740213274Srpaulo BFD_ENDIAN_LITTLE, /* Data byte order is little. */ 741213274Srpaulo BFD_ENDIAN_LITTLE, /* Header byte order is little. */ 742213274Srpaulo 743213274Srpaulo (HAS_RELOC | EXEC_P | /* Object flags. */ 744213274Srpaulo HAS_LINENO | HAS_DEBUG | 745213274Srpaulo HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), 746213274Srpaulo 747213274Srpaulo (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* Section flags. */ 748213274Srpaulo#if defined(COFF_WITH_PE) 749213274Srpaulo | SEC_LINK_ONCE | SEC_LINK_DUPLICATES | SEC_READONLY 750213274Srpaulo#endif 751213274Srpaulo | SEC_CODE | SEC_DATA), 752213274Srpaulo 753213274Srpaulo#ifdef TARGET_UNDERSCORE 754213274Srpaulo TARGET_UNDERSCORE, /* Leading underscore. */ 755213274Srpaulo#else 756213274Srpaulo 0, /* Leading underscore. */ 757213274Srpaulo#endif 758213274Srpaulo '/', /* Ar_pad_char. */ 759213274Srpaulo 15, /* Ar_max_namelen. */ 760213274Srpaulo 761213274Srpaulo bfd_getl64, bfd_getl_signed_64, bfd_putl64, 762213274Srpaulo bfd_getl32, bfd_getl_signed_32, bfd_putl32, 763213274Srpaulo bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Data. */ 764213274Srpaulo bfd_getl64, bfd_getl_signed_64, bfd_putl64, 765213274Srpaulo bfd_getl32, bfd_getl_signed_32, bfd_putl32, 766213274Srpaulo bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Hdrs. */ 767213274Srpaulo 768213274Srpaulo /* Note that we allow an object file to be treated as a core file as well. */ 769213274Srpaulo { _bfd_dummy_target, amd64coff_object_p, /* BFD_check_format. */ 770213274Srpaulo bfd_generic_archive_p, amd64coff_object_p }, 771213274Srpaulo { bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format. */ 772213274Srpaulo bfd_false }, 773213274Srpaulo { bfd_false, coff_write_object_contents, /* bfd_write_contents. */ 774213274Srpaulo _bfd_write_archive_contents, bfd_false }, 775213274Srpaulo 776213274Srpaulo BFD_JUMP_TABLE_GENERIC (coff), 777213274Srpaulo BFD_JUMP_TABLE_COPY (coff), 778213274Srpaulo BFD_JUMP_TABLE_CORE (_bfd_nocore), 779213274Srpaulo BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), 780213274Srpaulo BFD_JUMP_TABLE_SYMBOLS (coff), 781213274Srpaulo BFD_JUMP_TABLE_RELOCS (coff), 782213274Srpaulo BFD_JUMP_TABLE_WRITE (coff), 783213274Srpaulo BFD_JUMP_TABLE_LINK (coff), 784213274Srpaulo BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), 785213274Srpaulo 786213274Srpaulo NULL, 787213274Srpaulo 788213274Srpaulo COFF_SWAP_TABLE 789213274Srpaulo}; 790