1/* fixes.h (was taken from write.c in the original GAS)
2   Copyright (C) 1986,1987 Free Software Foundation, Inc.
3
4This file is part of GAS, the GNU Assembler.
5
6GAS is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GAS is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GAS; see the file COPYING.  If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20/* FROM line 25 */
21#include "as.h"
22
23#include "sections.h"
24#include "obstack.h"
25#include "frags.h"
26#include "fixes.h"
27#include "symbols.h"
28#include "input-scrub.h"
29#include <mach-o/x86_64/reloc.h>
30
31
32static fixS *
33fix_new_internal (fragS	*frag,		/* Which frag? */
34		  int	where,		/* where in that frag? */
35		  int	size,		/* 1, 2 or 4 bytes */
36		  symbolS *add_symbol,	/* X_add_symbol */
37		  symbolS *sub_symbol,	/* X_subtract_symbol */
38		  signed_target_addr_t offset,		/* X_add_number */
39		  int	pcrel,		/* TRUE if PC-relative relocation */
40		  int	pcrel_reloc,	/* TRUE if must have relocation entry */
41		  int	r_type)		/* relocation type */
42{
43    struct fix *fixP;
44
45	fixP = (struct fix *)obstack_alloc(&notes, sizeof(struct fix));
46
47	fixP->fx_frag	     = frag;
48	fixP->fx_where       = where;
49	fixP->fx_size	     = size;
50	fixP->fx_addsy       = add_symbol;
51	fixP->fx_subsy       = sub_symbol;
52	fixP->fx_offset      = offset;
53	fixP->fx_pcrel       = pcrel;
54	fixP->fx_pcrel_reloc = pcrel_reloc;
55	fixP->fx_r_type      = r_type;
56	fixP->fx_sectdiff_divide_by_two = 0;
57#if defined(I386) && defined(ARCH64)
58	if(fixP->fx_r_type == X86_64_RELOC_SIGNED){
59		switch(offset){
60			case -1:
61				fixP->fx_r_type = X86_64_RELOC_SIGNED_1;
62				break;
63			case -2:
64				fixP->fx_r_type = X86_64_RELOC_SIGNED_2;
65				break;
66			case -4:
67				fixP->fx_r_type = X86_64_RELOC_SIGNED_4;
68				break;
69			default:
70				break;
71		}
72	}
73	if(fixP->fx_r_type == X86_64_RELOC_GOT ||
74	   fixP->fx_r_type == X86_64_RELOC_GOT_LOAD){
75		/*
76		 * GOT and GOT_LOAD relocs are always PC-relative and
77		 * should not be converted to non-PC-relative addressing
78		 * later.
79		 */
80		fixP->fx_pcrel = TRUE;
81		fixP->fx_pcrel_reloc = TRUE;
82	}
83	/* We don't need this for non-local symbols, but it doesn't hurt. */
84	fixP->fx_localsy = symbol_new("L0\002", N_SECT, frchain_now->frch_nsect,
85	                              0, where, frag);
86	symbol_assign_index(fixP->fx_localsy);
87#endif
88	as_file_and_line (&fixP->file, &fixP->line);
89
90	fixP->fx_next              = frchain_now->frch_fix_root;
91	frchain_now->frch_fix_root = fixP;
92
93	return fixP;
94}
95
96#include "expr.h" /* HACK */
97/*
98 * fix_new() creates a fixS in obstack 'notes'.
99 */
100fixS *
101fix_new(
102fragS	*frag,		/* which frag? */
103int	where,		/* where in that frag? */
104int	size,		/* 1, 2 or 4 bytes */
105symbolS *add_symbol,	/* X_add_symbol */
106symbolS *sub_symbol,	/* X_subtract_symbol */
107	signed_target_addr_t
108	offset,		/* X_add_number */
109int	pcrel,		/* TRUE if PC-relative relocation */
110int	pcrel_reloc,	/* TRUE if must have relocation entry */
111int	r_type)		/* relocation type */
112{
113  return fix_new_internal (frag, where, size, add_symbol,
114			   sub_symbol, offset, pcrel, pcrel_reloc, r_type);
115}
116
117/* FROM write.c line 291 */
118typedef int RELOC_ENUM;
119#define X_op X_seg
120#define X_op_symbol X_add_symbol
121/* Create a fixup for an expression.  Currently we only support fixups
122   for difference expressions.  That is itself more than most object
123   file formats support anyhow.  */
124
125fixS *
126fix_new_exp (fragS *frag,		/* Which frag?  */
127	     int where,			/* Where in that frag?  */
128	     int size,			/* 1, 2, or 4 usually.  */
129	     expressionS *exp,		/* Expression.  */
130	     int pcrel,			/* TRUE if PC-relative relocation.  */
131	     int pcrel_reloc,		/* TRUE if must have relocation entry */
132	     RELOC_ENUM r_type		/* Relocation type.  */)
133{
134  symbolS *add = NULL;
135  symbolS *sub = NULL;
136  offsetT off = 0;
137
138  switch (exp->X_op)
139    {
140#ifdef NOTYET
141    case O_absent:
142      break;
143
144    case O_register:
145      as_bad (_("register value used as expression"));
146      break;
147
148    case O_add:
149      /* This comes up when _GLOBAL_OFFSET_TABLE_+(.-L0) is read, if
150	 the difference expression cannot immediately be reduced.  */
151      {
152	symbolS *stmp = make_expr_symbol (exp);
153
154	exp->X_op = O_symbol;
155	exp->X_op_symbol = 0;
156	exp->X_add_symbol = stmp;
157	exp->X_add_number = 0;
158
159	return fix_new_exp (frag, where, size, exp, pcrel, r_type);
160      }
161
162    case O_symbol_rva:
163      add = exp->X_add_symbol;
164      off = exp->X_add_number;
165
166#if defined(BFD_ASSEMBLER)
167      r_type = BFD_RELOC_RVA;
168#else
169#if defined(TC_RVA_RELOC)
170      r_type = TC_RVA_RELOC;
171#else
172      as_fatal (_("rva not supported"));
173#endif
174#endif
175      break;
176
177    case O_uminus:
178      sub = exp->X_add_symbol;
179      off = exp->X_add_number;
180      break;
181
182    case O_subtract:
183      sub = exp->X_op_symbol;
184      /* Fall through.  */
185#endif
186    case O_symbol:
187      add = exp->X_add_symbol;
188      /* Fall through.  */
189    case O_constant:
190      off = exp->X_add_number;
191      break;
192
193    default:
194      add = make_expr_symbol (exp);
195      break;
196    }
197
198  return fix_new_internal (frag, where, size, add, sub, off, pcrel, pcrel_reloc, r_type);
199}
200