2006-12-11 Gwenole Beauchesne <gbeauchesne@mandriva.com> * gas/config/tc-ppc.c (ppc_get_obj64): New. Handle run-time detection of 32-bit personality on Linux for ppc64 so that 32-bit code can be generated. (ppc_set_obj64): New. (md_parse_option): Use it. 2005-01-19 Gwenole Beauchesne <gbeauchesne@mandrakesoft.com> * gas/config/tc-i386.c (is_linux32): New. (get_default_arch): Handle detection of 32-bit personality on Linux for x86-64 so that 32-bit code can be generated. (set_default_arch): New. (md_parse_option): Use it. (i386_mach): Use new default_arch accessors. (i386_target_format): Likewise. --- binutils-2.17.50.0.8/gas/config/tc-ppc.c.linux32 2006-11-27 23:21:04.000000000 +0100 +++ binutils-2.17.50.0.8/gas/config/tc-ppc.c 2007-01-03 15:46:03.000000000 +0100 @@ -35,6 +35,10 @@ #include "coff/pe.h" #endif +#if defined(__linux__) && defined(__powerpc64__) +#include <sys/utsname.h> +#endif + /* This is the assembler for the PowerPC or POWER (RS/6000) chips. */ /* Tell the main code what the endianness is. */ @@ -92,6 +96,8 @@ static unsigned long ppc_insert_operand static void ppc_macro PARAMS ((char *str, const struct powerpc_macro *macro)); static void ppc_byte PARAMS ((int)); +static void ppc_set_obj64 PARAMS ((int)); + #if defined (OBJ_XCOFF) || defined (OBJ_ELF) static int ppc_is_toc_sym PARAMS ((symbolS *sym)); static void ppc_tc PARAMS ((int)); @@ -703,7 +709,7 @@ ppc_parse_name (name, expr) static unsigned long ppc_cpu = 0; /* Whether to target xcoff64/elf64. */ -static unsigned int ppc_obj64 = BFD_DEFAULT_TARGET_SIZE == 64; +static int g_ppc_obj64 = -1; /* Opcode hash table. */ static struct hash_control *ppc_hash; @@ -995,13 +1001,13 @@ md_parse_option (c, arg) if (strcmp (arg, "64") == 0) { #ifdef BFD64 - ppc_obj64 = 1; + ppc_set_obj64 (1); #else as_fatal (_("%s unsupported"), "-a64"); #endif } else if (strcmp (arg, "32") == 0) - ppc_obj64 = 0; + ppc_set_obj64 (0); else return 0; break; @@ -1148,6 +1154,37 @@ PowerPC options:\n\ #endif } +/* Set ppc_obj64 if it is not already set. */ + +#define ppc_obj64 (ppc_get_obj64 ()) + +static unsigned int +ppc_get_obj64 (void) +{ + if (g_ppc_obj64 < 0) + { + g_ppc_obj64 = BFD_DEFAULT_TARGET_SIZE == 64; + +#if defined(__linux__) && defined(__powerpc64__) + /* Determine if we are running under a 32-bit personality. Don't + use plain personality(0xffffffff) syscall because the kernel lies. */ + { + struct utsname buf; + if (uname(&buf) == 0 && strcmp(buf.machine, "ppc") == 0) + g_ppc_obj64 = 0; + } +#endif + } + + return g_ppc_obj64; +} + +static void +ppc_set_obj64 (int obj64) +{ + g_ppc_obj64 = obj64; +} + /* Set ppc_cpu if it is not already set. */ static void --- binutils-2.17.50.0.8/gas/config/tc-i386.c.linux32 2006-11-27 23:21:04.000000000 +0100 +++ binutils-2.17.50.0.8/gas/config/tc-i386.c 2007-01-03 15:48:19.000000000 +0100 @@ -35,6 +35,13 @@ #include "opcode/i386.h" #include "elf/x86-64.h" +#if defined(__linux__) && defined(__x86_64__) +#include <sys/syscall.h> +#include <sys/personality.h> + +#define is_linux32() ((syscall(SYS_personality, 0xffffffff) & PER_MASK) == PER_LINUX32) +#endif + #ifndef REGISTER_WARNINGS #define REGISTER_WARNINGS 1 #endif @@ -117,7 +124,16 @@ static void s_bss PARAMS ((int)); static void handle_large_common (int small ATTRIBUTE_UNUSED); #endif -static const char *default_arch = DEFAULT_ARCH; +enum x86_arch + { + ARCH_default, + ARCH_i386, + ARCH_x86_64 + }; + +static enum x86_arch g_default_arch = ARCH_default; +static enum x86_arch get_default_arch PARAMS ((void)); +static INLINE void set_default_arch PARAMS ((enum x86_arch arch)); /* 'md_assemble ()' gathers together information and puts it into a i386_insn. */ @@ -1204,15 +1220,46 @@ set_cpu_arch (dummy) demand_empty_rest_of_line (); } +static enum x86_arch +get_default_arch () +{ + const char *default_arch_str = DEFAULT_ARCH; + + if (g_default_arch != ARCH_default) + return g_default_arch; + +#ifdef is_linux32 + if (is_linux32 ()) + default_arch_str = "i386"; +#endif + + if (!strcmp (default_arch_str, "x86_64")) + g_default_arch = ARCH_x86_64; + else if (!strcmp (default_arch_str, "i386")) + g_default_arch = ARCH_i386; + + return g_default_arch; +} + +static INLINE void +set_default_arch (arch) + enum x86_arch arch; +{ + g_default_arch = arch; +} + unsigned long i386_mach () { - if (!strcmp (default_arch, "x86_64")) - return bfd_mach_x86_64; - else if (!strcmp (default_arch, "i386")) - return bfd_mach_i386_i386; - else - as_fatal (_("Unknown architecture")); + switch (get_default_arch ()) + { + case ARCH_x86_64: + return bfd_mach_x86_64; + case ARCH_i386: + return bfd_mach_i386_i386; + default: + as_fatal (_("Unknown architecture")); + } } void @@ -5887,7 +5934,7 @@ md_parse_option (int c, char *arg) || strcmp (*l, "pe-x86-64") == 0 || strcmp (*l, "pei-x86-64") == 0) { - default_arch = "x86_64"; + set_default_arch (ARCH_x86_64); break; } if (*l == NULL) @@ -5898,7 +5945,7 @@ md_parse_option (int c, char *arg) #endif case OPTION_32: - default_arch = "i386"; + set_default_arch (ARCH_i386); break; case OPTION_DIVIDE: @@ -6021,8 +6068,9 @@ x86_64_target_format (void) const char * i386_target_format () { - if (!strcmp (default_arch, "x86_64")) + switch (get_default_arch ()) { + case ARCH_x86_64: set_code_flag (CODE_64BIT); if (cpu_arch_isa_flags == 0) cpu_arch_isa_flags = Cpu186|Cpu286|Cpu386|Cpu486 @@ -6032,17 +6080,18 @@ i386_target_format () cpu_arch_tune_flags = Cpu186|Cpu286|Cpu386|Cpu486 |Cpu586|Cpu686|CpuP4|CpuMMX|CpuMMX2 |CpuSSE|CpuSSE2; - } - else if (!strcmp (default_arch, "i386")) - { + break; + case ARCH_i386: set_code_flag (CODE_32BIT); if (cpu_arch_isa_flags == 0) cpu_arch_isa_flags = Cpu186|Cpu286|Cpu386; if (cpu_arch_tune_flags == 0) cpu_arch_tune_flags = Cpu186|Cpu286|Cpu386; + break; + default: + as_fatal (_("Unknown architecture")); + break; } - else - as_fatal (_("Unknown architecture")); switch (OUTPUT_FLAVOR) { #ifdef OBJ_MAYBE_AOUT