aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-i386.c
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2015-05-15 03:17:31 -0700
committerH.J. Lu <hjl.tools@gmail.com>2015-05-15 03:30:53 -0700
commit8dcea93252a9ea7dff57e85220a719e2a5e8ab41 (patch)
treec2e6a597a60a10a48c58f9a6e95cb117f65f8fe4 /gas/config/tc-i386.c
parentd1c4b12b9d48d9266b78e2c22d70aa25830b9f8f (diff)
downloadgdb-8dcea93252a9ea7dff57e85220a719e2a5e8ab41.zip
gdb-8dcea93252a9ea7dff57e85220a719e2a5e8ab41.tar.gz
gdb-8dcea93252a9ea7dff57e85220a719e2a5e8ab41.tar.bz2
Add -mshared option to x86 ELF assembler
This patch adds -mshared option to x86 ELF assembler. By default, assembler will optimize out non-PLT relocations against defined non-weak global branch targets with default visibility. The -mshared option tells the assembler to generate code which may go into a shared library where all non-weak global branch targets with default visibility can be preempted. The resulting code is slightly bigger. This option only affects the handling of branch instructions. This Linux kernel patch is needed to create a working x86 Linux kernel if it hasn't been applied: diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index ae6588b..b91a00c 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -339,8 +339,8 @@ early_idt_handlers: i = i + 1 .endr -/* This is global to keep gas from relaxing the jumps */ -ENTRY(early_idt_handler) +/* This is weak to keep gas from relaxing the jumps */ +WEAK(early_idt_handler) cld cmpl $2,(%rsp) # X86_TRAP_NMI -- gas/ * config/tc-i386.c (shared): New. (OPTION_MSHARED): Likewise. (elf_symbol_resolved_in_segment_p): Add relocation argument. Check PLT relocations and shared. (md_estimate_size_before_relax): Pass fragP->fr_var to elf_symbol_resolved_in_segment_p. (md_longopts): Add -mshared. (md_show_usage): Likewise. (md_parse_option): Handle OPTION_MSHARED. * doc/c-i386.texi: Document -mshared. gas/testsuite/ * gas/i386/i386.exp: Don't run pcrel for ELF targets. Run pcrel-elf, relax-4 and x86-64-relax-3 for ELF targets. * gas/i386/pcrel-elf.d: New file. * gas/i386/relax-4.d: Likewise. * gas/i386/x86-64-relax-3.d: Likewise. * gas/i386/relax-3.d: Pass -mshared to assembler. Updated. * gas/i386/x86-64-relax-2.d: Likewise. * gas/i386/relax-3.s: Add test for PLT relocation.
Diffstat (limited to 'gas/config/tc-i386.c')
-rw-r--r--gas/config/tc-i386.c35
1 files changed, 32 insertions, 3 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 75f268f..254548f 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -524,6 +524,11 @@ static enum x86_elf_abi x86_elf_abi = I386_ABI;
static int use_big_obj = 0;
#endif
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+/* 1 if generating code for a shared library. */
+static int shared = 0;
+#endif
+
/* 1 for intel syntax,
0 if att syntax. */
static int intel_syntax = 0;
@@ -8818,7 +8823,7 @@ i386_frag_max_var (fragS *frag)
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
static int
-elf_symbol_resolved_in_segment_p (symbolS *fr_symbol)
+elf_symbol_resolved_in_segment_p (symbolS *fr_symbol, offsetT fr_var)
{
/* STT_GNU_IFUNC symbol must go through PLT. */
if ((symbol_get_bfdsym (fr_symbol)->flags
@@ -8829,9 +8834,24 @@ elf_symbol_resolved_in_segment_p (symbolS *fr_symbol)
/* Symbol may be weak or local. */
return !S_IS_WEAK (fr_symbol);
+ /* Global symbols with non-default visibility can't be preempted. */
+ if (ELF_ST_VISIBILITY (S_GET_OTHER (fr_symbol)) != STV_DEFAULT)
+ return 1;
+
+ if (fr_var != NO_RELOC)
+ switch ((enum bfd_reloc_code_real) fr_var)
+ {
+ case BFD_RELOC_386_PLT32:
+ case BFD_RELOC_X86_64_PLT32:
+ /* Symbol with PLT relocatin may be preempted. */
+ return 0;
+ default:
+ abort ();
+ }
+
/* Global symbols with default visibility in a shared library may be
preempted by another definition. */
- return ELF_ST_VISIBILITY (S_GET_OTHER (fr_symbol)) != STV_DEFAULT;
+ return !shared;
}
#endif
@@ -8858,7 +8878,8 @@ md_estimate_size_before_relax (fragS *fragP, segT segment)
if (S_GET_SEGMENT (fragP->fr_symbol) != segment
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
|| (IS_ELF
- && !elf_symbol_resolved_in_segment_p (fragP->fr_symbol))
+ && !elf_symbol_resolved_in_segment_p (fragP->fr_symbol,
+ fragP->fr_var))
#endif
#if defined (OBJ_COFF) && defined (TE_PE)
|| (OUTPUT_FLAVOR == bfd_target_coff_flavour
@@ -9528,6 +9549,7 @@ const char *md_shortopts = "qn";
#define OPTION_MBIG_OBJ (OPTION_MD_BASE + 18)
#define OPTION_OMIT_LOCK_PREFIX (OPTION_MD_BASE + 19)
#define OPTION_MEVEXRCIG (OPTION_MD_BASE + 20)
+#define OPTION_MSHARED (OPTION_MD_BASE + 21)
struct option md_longopts[] =
{
@@ -9538,6 +9560,7 @@ struct option md_longopts[] =
#endif
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
{"x32", no_argument, NULL, OPTION_X32},
+ {"mshared", no_argument, NULL, OPTION_MSHARED},
#endif
{"divide", no_argument, NULL, OPTION_DIVIDE},
{"march", required_argument, NULL, OPTION_MARCH},
@@ -9598,6 +9621,10 @@ md_parse_option (int c, char *arg)
/* -s: On i386 Solaris, this tells the native assembler to use
.stab instead of .stab.excl. We always use .stab anyhow. */
break;
+
+ case OPTION_MSHARED:
+ shared = 1;
+ break;
#endif
#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \
|| defined (TE_PE) || defined (TE_PEP) || defined (OBJ_MACH_O))
@@ -10027,6 +10054,8 @@ md_show_usage (FILE *stream)
-mold-gcc support old (<= 2.8.1) versions of gcc\n"));
fprintf (stream, _("\
-madd-bnd-prefix add BND prefix for all valid branches\n"));
+ fprintf (stream, _("\
+ -mshared disable branch optimization for shared code\n"));
# if defined (TE_PE) || defined (TE_PEP)
fprintf (stream, _("\
-mbig-obj generate big object files\n"));