aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>1999-09-13 06:45:15 +0000
committerAlan Modra <amodra@gmail.com>1999-09-13 06:45:15 +0000
commit2f66722d5578761036ef07bf98897e2d119dbf10 (patch)
treee51672933b983048d8a14f08f2bbf7d135fe26e4 /gas
parent9169713a19c18ec43b3cf831daecc1aa68361724 (diff)
downloadfsf-binutils-gdb-2f66722d5578761036ef07bf98897e2d119dbf10.zip
fsf-binutils-gdb-2f66722d5578761036ef07bf98897e2d119dbf10.tar.gz
fsf-binutils-gdb-2f66722d5578761036ef07bf98897e2d119dbf10.tar.bz2
Hackery to handle ix86 "jmp constant" as a pc-relative jump to the given
absolute address.
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog5
-rw-r--r--gas/config/tc-i386.c156
2 files changed, 56 insertions, 105 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 41f0dce..a52924a 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,5 +1,10 @@
1999-09-13 Alan Modra <alan@spri.levels.unisa.edu.au>
+ * config/tc-i386.c (md_assemble): Handle "jmp/call constant" as a
+ pc-relative jmp/call to an absolute symbol.
+ (md_apply_fix3): When OBJ_ELF, don't add the values in twice for
+ absolute section symbols.
+
* config/tc-i386.c (md_assemble): Correct frag_var size. Tidy
jump handling code and comments.
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 197387a..a8055cc 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -2085,6 +2085,16 @@ md_assemble (line)
i.imm_operands = 0;
}
+ if ((i.tm.opcode_modifier & (Jump | JumpByte | JumpDword))
+ && i.disps[0]->X_op == O_constant)
+ {
+ /* Convert "jmp constant" (and "call constant") to a jump (call) to
+ the absolute address given by the constant. Since ix86 jumps and
+ calls are pc relative, we need to generate a reloc. */
+ i.disps[0]->X_add_symbol = &abs_symbol;
+ i.disps[0]->X_op = O_symbol;
+ }
+
/* We are ready to output the insn. */
{
register char *p;
@@ -2115,77 +2125,28 @@ md_assemble (line)
if (i.prefixes != 0 && !intel_syntax)
as_warn (_("skipping prefixes on this instruction"));
- if (i.disps[0]->X_op == O_constant)
- {
- long n = (long) i.disps[0]->X_add_number;
-
- if (fits_in_signed_byte (n))
- {
- insn_size += 2;
- p = frag_more (2);
- p[0] = i.tm.base_opcode;
- p[1] = n;
- }
- else
- {
- /* Use 16-bit jumps only for 16-bit code,
- because text segments are limited to 64K anyway;
- Use 32-bit jumps for 32-bit code, because they're faster,
- and a 16-bit jump will clear the top 16 bits of %eip. */
- if (code16 && !fits_in_signed_word (n))
- {
- as_bad (_("16-bit jump out of range"));
- return;
- }
-
- if (i.tm.base_opcode == JUMP_PC_RELATIVE)
- { /* pace */
- /* unconditional jump */
- insn_size += prefix + 1 + size;
- p = frag_more (prefix + 1 + size);
- if (prefix)
- *p++ = DATA_PREFIX_OPCODE;
- *p++ = (char) 0xe9;
- md_number_to_chars (p, (valueT) n, size);
- }
- else
- {
- /* conditional jump */
- insn_size += prefix + 2 + size;
- p = frag_more (prefix + 2 + size);
- if (prefix)
- *p++ = DATA_PREFIX_OPCODE;
- *p++ = TWO_BYTE_OPCODE_ESCAPE;
- *p++ = i.tm.base_opcode + 0x10;
- md_number_to_chars (p, (valueT) n, size);
- }
- }
- }
- else
- {
- /* It's a symbol; End frag & setup for relax.
- Make sure there is enough room in this frag for the largest
- instruction we may generate in md_convert_frag. This is 2
- bytes for the opcode and room for the prefix and largest
- displacement. */
- frag_grow (prefix + 2 + size);
- insn_size += prefix + 1;
- /* Prefix and 1 opcode byte go in fr_fix. */
- p = frag_more (prefix + 1);
- if (prefix)
- *p++ = DATA_PREFIX_OPCODE;
- *p = i.tm.base_opcode;
- /* 1 possible extra opcode + displacement go in fr_var */
- frag_var (rs_machine_dependent,
- 1 + size,
- 1,
- ((unsigned char) *p == JUMP_PC_RELATIVE
- ? ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL) | code16
- : ENCODE_RELAX_STATE (COND_JUMP, SMALL) | code16),
- i.disps[0]->X_add_symbol,
- i.disps[0]->X_add_number,
- p);
- }
+ /* It's always a symbol; End frag & setup for relax.
+ Make sure there is enough room in this frag for the largest
+ instruction we may generate in md_convert_frag. This is 2
+ bytes for the opcode and room for the prefix and largest
+ displacement. */
+ frag_grow (prefix + 2 + size);
+ insn_size += prefix + 1;
+ /* Prefix and 1 opcode byte go in fr_fix. */
+ p = frag_more (prefix + 1);
+ if (prefix)
+ *p++ = DATA_PREFIX_OPCODE;
+ *p = i.tm.base_opcode;
+ /* 1 possible extra opcode + displacement go in fr_var. */
+ frag_var (rs_machine_dependent,
+ 1 + size,
+ 1,
+ ((unsigned char) *p == JUMP_PC_RELATIVE
+ ? ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL) | code16
+ : ENCODE_RELAX_STATE (COND_JUMP, SMALL) | code16),
+ i.disps[0]->X_add_symbol,
+ i.disps[0]->X_add_number,
+ p);
}
else if (i.tm.opcode_modifier & (JumpByte | JumpDword))
{
@@ -2240,28 +2201,8 @@ md_assemble (line)
}
*p++ = i.tm.base_opcode & 0xff;
- if (i.disps[0]->X_op == O_constant)
- {
- long n = (long) i.disps[0]->X_add_number;
-
- if (size == 1 && !fits_in_signed_byte (n))
- {
- as_bad (_("`%s' only takes byte displacement; %ld shortened to %d"),
- i.tm.name, n, *p);
- }
- else if (size == 2 && !fits_in_signed_word (n))
- {
- as_bad (_("16-bit jump out of range"));
- return;
- }
- md_number_to_chars (p, (valueT) n, size);
- }
- else
- {
- fix_new_exp (frag_now, p - frag_now->fr_literal, size,
- i.disps[0], 1, reloc (size, 1, i.disp_reloc[0]));
-
- }
+ fix_new_exp (frag_now, p - frag_now->fr_literal, size,
+ i.disps[0], 1, reloc (size, 1, i.disp_reloc[0]));
}
else if (i.tm.opcode_modifier & JumpInterSegment)
{
@@ -3912,19 +3853,24 @@ md_apply_fix3 (fixP, valp, seg)
value += fixP->fx_where + fixP->fx_frag->fr_address;
#endif
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
- if (OUTPUT_FLAVOR == bfd_target_elf_flavour
- && (S_GET_SEGMENT (fixP->fx_addsy) == seg
- || symbol_section_p (fixP->fx_addsy))
- && ! S_IS_EXTERNAL (fixP->fx_addsy)
- && ! S_IS_WEAK (fixP->fx_addsy)
- && S_IS_DEFINED (fixP->fx_addsy)
- && ! S_IS_COMMON (fixP->fx_addsy))
+ if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
{
- /* Yes, we add the values in twice. This is because
- bfd_perform_relocation subtracts them out again. I think
- bfd_perform_relocation is broken, but I don't dare change
- it. FIXME. */
- value += fixP->fx_where + fixP->fx_frag->fr_address;
+ segT fseg = S_GET_SEGMENT (fixP->fx_addsy);
+
+ if ((fseg == seg
+ || (symbol_section_p (fixP->fx_addsy)
+ && fseg != absolute_section))
+ && ! S_IS_EXTERNAL (fixP->fx_addsy)
+ && ! S_IS_WEAK (fixP->fx_addsy)
+ && S_IS_DEFINED (fixP->fx_addsy)
+ && ! S_IS_COMMON (fixP->fx_addsy))
+ {
+ /* Yes, we add the values in twice. This is because
+ bfd_perform_relocation subtracts them out again. I think
+ bfd_perform_relocation is broken, but I don't dare change
+ it. FIXME. */
+ value += fixP->fx_where + fixP->fx_frag->fr_address;
+ }
}
#endif
#if defined (OBJ_COFF) && defined (TE_PE)