diff -ruN binutils-2.28/bfd/elf32-ppc.c binutils-2.28-vle/bfd/elf32-ppc.c --- binutils-2.28/bfd/elf32-ppc.c 2017-03-02 11:23:53.000000000 +0300 +++ binutils-2.28-vle/bfd/elf32-ppc.c 2017-06-23 22:01:57.953766000 +0300 @@ -171,6 +171,9 @@ #define NOP 0x60000000 #define SUB_11_11_12 0x7d6c5850 +/* VLE some instructions */ +#define E_B 0x78000000 + /* Offset of tp and dtp pointers from start of TLS block. */ #define TP_OFFSET 0x7000 #define DTP_OFFSET 0x8000 @@ -1444,6 +1447,21 @@ 0x1fffffe, /* dst_mask */ TRUE), /* pcrel_offset */ + /* A relative 24 bit branch. */ + HOWTO (R_PPC_VLE_PLTREL24, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 24, /* bitsize */ + TRUE, /* pc_relative */ + 1, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ + "R_PPC_VLE_PLTREL24", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x1fffffe, /* dst_mask */ + TRUE), /* pcrel_offset */ + /* The 16 LSBS in split16a format. */ HOWTO (R_PPC_VLE_LO16A, /* type */ 0, /* rightshift */ @@ -1656,6 +1674,21 @@ 0x3e007ff, /* dst_mask */ FALSE), /* pcrel_offset */ + /* e_li split20 format. */ + HOWTO (R_PPC_VLE_ADDR20, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_VLE_ADDR20", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x1f07ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + HOWTO (R_PPC_IRELATIVE, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ @@ -2463,6 +2496,14 @@ return 0; } +static bfd_boolean +ppc_elf_section_flags (flagword *flags, const Elf_Internal_Shdr * hdr) +{ + if (hdr->sh_flags & SHF_PPC_VLE) + *flags |= SEC_PPC_VLE; + return TRUE; +} + /* Return address for Ith PLT stub in section PLT, for relocation REL or (bfd_vma) -1 if it should not be included. */ @@ -2511,6 +2552,8 @@ { if ((asect->flags & SEC_SORT_ENTRIES) != 0) shdr->sh_type = SHT_ORDERED; + if ((asect->flags & SEC_PPC_VLE) != 0) + shdr->sh_flags |= SHF_PPC_VLE; return TRUE; } @@ -4247,6 +4290,7 @@ case R_PPC_VLE_HI16D: case R_PPC_VLE_HA16A: case R_PPC_VLE_HA16D: + case R_PPC_VLE_ADDR20: break; case R_PPC_EMB_SDA2REL: @@ -4294,6 +4338,7 @@ break; case R_PPC_PLTREL24: + case R_PPC_VLE_PLTREL24: if (h == NULL) break; /* Fall through */ @@ -4365,6 +4410,7 @@ case R_PPC_NONE: case R_PPC_max: case R_PPC_RELAX: + case R_PPC_VLE_RELAX: case R_PPC_RELAX_PLT: case R_PPC_RELAX_PLTREL24: case R_PPC_16DX_HA: @@ -4965,6 +5011,23 @@ insn |= value & 0x7ff; bfd_put_32 (input_bfd, insn, loc); } + +static void +ppc_elf_vle_split20 (bfd *output_bfd, bfd_byte *loc, bfd_vma value) +{ + unsigned int insn; + + insn = bfd_get_32 (output_bfd, loc); + /* We have an li20 field, bits 17..20, 11..15, 21..31. */ + /* Top 4 bits of value to 17..20. */ + insn |= (value & 0xf0000) >> 5; + /* Next 5 bits of the value to 11..15. */ + insn |= (value & 0xf800) << 5; + /* And the final 11 bits of the value to bits 21 to 31. */ + insn |= value & 0x7ff; + bfd_put_32 (output_bfd, insn, loc); +} + /* Choose which PLT scheme to use, and set .plt flags appropriately. Returns -1 on error, 0 for old PLT, 1 for new PLT. */ @@ -6907,6 +6970,13 @@ 0x4e800420, /* bctr */ }; +typedef enum ppc_target_stub_entry_type + { + stub_entry_type_ppc = 0, + stub_entry_type_vle + } +ppc_target_stub_entry_type; + static const int stub_entry[] = { 0x3d800000, /* lis 12,xxx@ha */ @@ -6915,6 +6985,15 @@ 0x4e800420, /* bctr */ }; +/* Keep the same size as stub_entry */ +static const int stub_entry_vle[] = + { + 0x7180e000, /* e_lis 12,xxx@ha */ + 0x1d8c0000, /* e_add16i 12,12,xxx@l */ + 0x7d8903a6, /* mtctr 12 */ + 0x00064400, /* se_bctr, se_nop (size padding) */ + }; + struct ppc_elf_relax_info { unsigned int workaround_size; @@ -6955,6 +7034,7 @@ bfd_size_type trampbase, trampoff, newsize, picfixup_size; asection *got2; bfd_boolean maybe_pasted; + ppc_target_stub_entry_type target_stub_type = 0; *again = FALSE; @@ -7035,21 +7115,43 @@ struct elf_link_hash_entry *h; struct plt_entry **plist; unsigned char sym_type; + reloc_howto_type *current_howto; + current_howto = NULL; switch (r_type) { case R_PPC_REL24: case R_PPC_LOCAL24PC: case R_PPC_PLTREL24: + target_stub_type = stub_entry_type_ppc; max_branch_offset = 1 << 25; break; case R_PPC_REL14: case R_PPC_REL14_BRTAKEN: case R_PPC_REL14_BRNTAKEN: + target_stub_type = stub_entry_type_ppc; max_branch_offset = 1 << 15; break; + case R_PPC_VLE_REL24: + target_stub_type = stub_entry_type_vle; + max_branch_offset = 1 << 25; + current_howto = ppc_elf_howto_table[r_type]; + break; + + case R_PPC_VLE_REL15: + target_stub_type = stub_entry_type_vle; + max_branch_offset = 1 << 16; + current_howto = ppc_elf_howto_table[r_type]; + break; + + case R_PPC_VLE_REL8: + target_stub_type = stub_entry_type_vle; + max_branch_offset = 1 << 9; + current_howto = ppc_elf_howto_table[r_type]; + break; + case R_PPC_ADDR16_HA: if (htab->params->pic_fixup > 0) break; @@ -7297,9 +7399,25 @@ symaddr = tsec->output_section->vma + tsec->output_offset + toff; reladdr = isec->output_section->vma + isec->output_offset + roff; - if (symaddr - reladdr + max_branch_offset - < 2 * max_branch_offset) - continue; + + /* I don't trust the relocation check using ' ... < (2 * max_branch_offset)' + * Check for overflow using the bfd API first. + */ + if (current_howto) /* current_howto is not necessarily defined for + all reloc types above, but use it if it is defined */ + { + if (bfd_check_overflow (current_howto->complain_on_overflow, + current_howto->bitsize, + current_howto->rightshift, + bfd_arch_bits_per_address(abfd), + (symaddr-reladdr)) == bfd_reloc_ok ) + continue; + } + else + { + if (((symaddr - reladdr) + max_branch_offset) < (2 * max_branch_offset)) + continue; + } } /* Look for an existing fixup to this address. */ @@ -7328,7 +7446,7 @@ size = 4 * ARRAY_SIZE (stub_entry); insn_offset = 0; } - stub_rtype = R_PPC_RELAX; + stub_rtype = (target_stub_type == stub_entry_type_vle) ? R_PPC_VLE_RELAX : R_PPC_RELAX; if (tsec == htab->elf.splt || tsec == htab->glink) { @@ -7385,10 +7503,21 @@ case R_PPC_REL24: case R_PPC_LOCAL24PC: case R_PPC_PLTREL24: - t0 = bfd_get_32 (abfd, hit_addr); - t0 &= ~0x3fffffc; - t0 |= val & 0x3fffffc; - bfd_put_32 (abfd, t0, hit_addr); + if (r_type == R_PPC_PLTREL24 + && (elf_section_flags (isec) & SHF_PPC_VLE) != 0) + { + t0 = bfd_get_32 (abfd, hit_addr); + t0 &= ~0x01fffffe; + t0 |= val & 0x01fffffe; + bfd_put_32 (abfd, t0, hit_addr); + } + else + { + t0 = bfd_get_32 (abfd, hit_addr); + t0 &= ~0x3fffffc; + t0 |= val & 0x3fffffc; + bfd_put_32 (abfd, t0, hit_addr); + } break; case R_PPC_REL14: @@ -7399,6 +7528,27 @@ t0 |= val & 0xfffc; bfd_put_32 (abfd, t0, hit_addr); break; + + case R_PPC_VLE_REL24: + t0 = bfd_get_32 (abfd, hit_addr); + t0 &= ~0x01fffffe; + t0 |= val & 0x01fffffe; + bfd_put_32 (abfd, t0, hit_addr); + break; + + case R_PPC_VLE_REL15: + t0 = bfd_get_32 (abfd, hit_addr); + t0 &= ~0xfffe; + t0 |= val & 0xfffe; + bfd_put_32 (abfd, t0, hit_addr); + break; + + case R_PPC_VLE_REL8: + t0 = bfd_get_32 (abfd, hit_addr); + t0 &= ~0xff; + t0 |= val & 0xff; + bfd_put_32 (abfd, t0, hit_addr); + break; } } @@ -9043,6 +9193,7 @@ /* Fall through. */ case R_PPC_RELAX: + case R_PPC_VLE_RELAX: { const int *stub; size_t size; @@ -9063,8 +9214,8 @@ } else { - stub = stub_entry; - size = ARRAY_SIZE (stub_entry); + stub = (r_type == R_PPC_VLE_RELAX) ? stub_entry_vle : stub_entry; + size = ARRAY_SIZE (stub_entry); /* stub_entry and stub_entry_vle must be same size */ } relocation += addend; @@ -9072,10 +9223,23 @@ relocation = 0; /* First insn is HA, second is LO. */ - insn = *stub++; - insn |= ((relocation + 0x8000) >> 16) & 0xffff; - bfd_put_32 (input_bfd, insn, contents + insn_offset); - insn_offset += 4; + if (r_type == R_PPC_VLE_RELAX) + { + /* Write e_lis insn is @ha type relocation */ + unsigned ha_val; + insn = *stub++; + ha_val = ((relocation + 0x8000) >> 16) & 0xffff; + insn |= (((ha_val & 0xf800) << 5) | (ha_val&0x7ff)); + bfd_put_32 (input_bfd, insn, contents + insn_offset); + insn_offset += 4; + } + else + { + insn = *stub++; + insn |= ((relocation + 0x8000) >> 16) & 0xffff; + bfd_put_32 (input_bfd, insn, contents + insn_offset); + insn_offset += 4; + } insn = *stub++; insn |= relocation & 0xffff; @@ -9482,6 +9646,10 @@ } goto copy_reloc; + case R_PPC_VLE_ADDR20: + ppc_elf_vle_split20 (output_bfd, contents + rel->r_offset, relocation); + continue; + /* Relocate against the beginning of the section. */ case R_PPC_SECTOFF: case R_PPC_SECTOFF_LO: @@ -9759,8 +9927,15 @@ && (strcmp (input_section->output_section->name, ".init") == 0 || strcmp (input_section->output_section->name, ".fini") == 0)) { + unsigned int insn; + + if ((elf_section_flags (input_section) & SHF_PPC_VLE) == 0) + insn = B; + else + insn = E_B; + /* Branch around the trampolines. */ - unsigned int insn = B + input_section->size - input_section->rawsize; + insn += input_section->size - input_section->rawsize; bfd_put_32 (input_bfd, insn, contents + input_section->rawsize); } @@ -10949,6 +11124,7 @@ #define elf_backend_action_discarded ppc_elf_action_discarded #define elf_backend_init_index_section _bfd_elf_init_1_index_section #define elf_backend_lookup_section_flags_hook ppc_elf_lookup_section_flags +#define elf_backend_section_flags ppc_elf_section_flags #include "elf32-target.h" diff -ruN binutils-2.28/binutils/objdump.c binutils-2.28-vle/binutils/objdump.c --- binutils-2.28/binutils/objdump.c 2017-03-02 11:23:53.000000000 +0300 +++ binutils-2.28-vle/binutils/objdump.c 2017-06-23 17:25:21.641299056 +0300 @@ -481,6 +481,10 @@ PF (SEC_NEVER_LOAD, "NEVER_LOAD"); PF (SEC_EXCLUDE, "EXCLUDE"); PF (SEC_SORT_ENTRIES, "SORT_ENTRIES"); + if (bfd_get_arch(abfd) == bfd_arch_powerpc || bfd_get_arch (abfd) == bfd_mach_ppc_vle) + { + PF (SEC_TIC54X_BLOCK, "VLE"); /* hack, would have to include ppc.h */ + } if (bfd_get_arch (abfd) == bfd_arch_tic54x) { PF (SEC_TIC54X_BLOCK, "BLOCK"); diff -ruN binutils-2.28/binutils/readelf.c binutils-2.28-vle/binutils/readelf.c --- binutils-2.28/binutils/readelf.c 2017-03-02 11:23:53.000000000 +0300 +++ binutils-2.28-vle/binutils/readelf.c 2017-06-23 21:51:24.753324000 +0300 @@ -5491,7 +5491,9 @@ /* ARM specific. */ /* 21 */ { STRING_COMMA_LEN ("ENTRYSECT") }, /* 22 */ { STRING_COMMA_LEN ("ARM_PURECODE") }, - /* 23 */ { STRING_COMMA_LEN ("COMDEF") } + /* 23 */ { STRING_COMMA_LEN ("COMDEF") }, + /* VLE specific. */ + /* 24 */ { STRING_COMMA_LEN ("VLE") } }; if (do_section_details) @@ -5524,6 +5526,7 @@ case SHF_TLS: sindex = 9; break; case SHF_EXCLUDE: sindex = 18; break; case SHF_COMPRESSED: sindex = 20; break; + case SHF_PPC_VLE: sindex = 24; break; default: sindex = -1; @@ -5617,6 +5620,7 @@ case SHF_TLS: *p = 'T'; break; case SHF_EXCLUDE: *p = 'E'; break; case SHF_COMPRESSED: *p = 'C'; break; + case SHF_PPC_VLE: *p = 'V'; break; default: if ((elf_header.e_machine == EM_X86_64 @@ -6333,6 +6337,8 @@ printf (_("l (large), ")); else if (elf_header.e_machine == EM_ARM) printf (_("y (purecode), ")); + else if (elf_header.e_machine == EM_PPC) + printf (_("V (VLE), ")); printf ("p (processor specific)\n"); } diff -ruN binutils-2.28/gas/config/obj-elf.c binutils-2.28-vle/gas/config/obj-elf.c --- binutils-2.28/gas/config/obj-elf.c 2017-03-02 11:23:53.000000000 +0300 +++ binutils-2.28-vle/gas/config/obj-elf.c 2017-06-23 17:26:08.784859055 +0300 @@ -677,6 +677,11 @@ /* RX init/fini arrays can and should have the "awx" attributes set. */ ; #endif +#ifdef TC_PPC + /* A section on powerpc-vle may have SHF_PPC_VLE. */ + else if ((attr & ~ssect->attr) == SHF_PPC_VLE) + override = TRUE; +#endif else { if (group_name == NULL) diff -ruN binutils-2.28/gas/config/tc-ppc.c binutils-2.28-vle/gas/config/tc-ppc.c --- binutils-2.28/gas/config/tc-ppc.c 2017-03-02 11:23:53.000000000 +0300 +++ binutils-2.28-vle/gas/config/tc-ppc.c 2017-06-23 17:48:51.463401055 +0300 @@ -1153,6 +1153,16 @@ } } + else if (strcmp (arg, "no-vle") == 0) + { + sticky &= ~PPC_OPCODE_VLE; + + new_cpu = ppc_parse_cpu (ppc_cpu, &sticky, "booke"); + new_cpu &= ~PPC_OPCODE_VLE; + + ppc_cpu = new_cpu; + } + else if (strcmp (arg, "regnames") == 0) reg_names_p = TRUE; @@ -3562,13 +3572,26 @@ } int -ppc_section_flags (flagword flags, bfd_vma attr ATTRIBUTE_UNUSED, int type) +ppc_section_flags (flagword flags, bfd_vma attr, int type) { if (type == SHT_ORDERED) flags |= SEC_ALLOC | SEC_LOAD | SEC_SORT_ENTRIES; + if (attr == SHF_PPC_VLE) + flags |= SEC_PPC_VLE; + return flags; } + +bfd_vma +ppc_elf_section_letter (int letter, const char **ptrmsg) +{ + if (letter == 'v') + return SHF_PPC_VLE; + + *ptrmsg = _("bad .section directive: want a,e,v,w,x,M,S,G,T in string"); + return -1; +} #endif /* OBJ_ELF */ diff -ruN binutils-2.28/gas/config/tc-ppc.h binutils-2.28-vle/gas/config/tc-ppc.h --- binutils-2.28/gas/config/tc-ppc.h 2017-03-02 11:23:53.000000000 +0300 +++ binutils-2.28-vle/gas/config/tc-ppc.h 2017-06-23 17:28:07.396135056 +0300 @@ -226,6 +226,9 @@ #define tc_comment_chars ppc_comment_chars extern const char *ppc_comment_chars; +#define md_elf_section_letter ppc_elf_section_letter +extern bfd_vma ppc_elf_section_letter (int, const char **); + /* Keep relocations relative to the GOT, or non-PC relative. */ #define tc_fix_adjustable(FIX) ppc_fix_adjustable (FIX) extern int ppc_fix_adjustable (struct fix *); diff -ruN binutils-2.28/gas/doc/as.texinfo binutils-2.28-vle/gas/doc/as.texinfo --- binutils-2.28/gas/doc/as.texinfo 2017-03-02 11:23:53.000000000 +0300 +++ binutils-2.28-vle/gas/doc/as.texinfo 2017-06-23 17:29:31.519652342 +0300 @@ -6495,6 +6495,8 @@ section is allocatable @item e section is excluded from executable and shared library. +@item v +section contains PowerPC VLE code (sets the SHF_PPC_VLE flag bit) @item w section is writable @item x diff -ruN binutils-2.28/include/elf/ppc.h binutils-2.28-vle/include/elf/ppc.h --- binutils-2.28/include/elf/ppc.h 2017-03-02 11:23:54.000000000 +0300 +++ binutils-2.28-vle/include/elf/ppc.h 2017-06-23 17:34:20.838930833 +0300 @@ -79,8 +79,10 @@ RELOC_NUMBER (R_PPC_RELAX, 48) RELOC_NUMBER (R_PPC_RELAX_PLT, 49) RELOC_NUMBER (R_PPC_RELAX_PLTREL24, 50) + RELOC_NUMBER (R_PPC_VLE_RELAX, 51) /* Reloc only used internally by gas. As above, value is unimportant. */ - RELOC_NUMBER (R_PPC_16DX_HA, 51) + RELOC_NUMBER (R_PPC_16DX_HA, 52) + RELOC_NUMBER (R_PPC_VLE_PLTREL24, 53) #endif /* Relocs added to support TLS. */ @@ -152,6 +154,7 @@ RELOC_NUMBER (R_PPC_VLE_SDAREL_HI16D, 230) RELOC_NUMBER (R_PPC_VLE_SDAREL_HA16A, 231) RELOC_NUMBER (R_PPC_VLE_SDAREL_HA16D, 232) + RELOC_NUMBER (R_PPC_VLE_ADDR20, 233) /* Power9 split rel16 for addpcis. */ RELOC_NUMBER (R_PPC_REL16DX_HA, 246) @@ -198,6 +201,9 @@ /* Processor specific section headers, sh_flags field. */ #define SHF_PPC_VLE 0x10000000 /* PowerPC VLE text section. */ +/* BFD section headers flag. */ +#define SEC_PPC_VLE SEC_TIC54X_BLOCK + /* Processor specific section headers, sh_type field. */ #define SHT_ORDERED SHT_HIPROC /* Link editor is to sort the \ diff -ruN binutils-2.28/opcodes/ppc-dis.c binutils-2.28-vle/opcodes/ppc-dis.c --- binutils-2.28/opcodes/ppc-dis.c 2017-03-02 11:23:54.000000000 +0300 +++ binutils-2.28-vle/opcodes/ppc-dis.c 2017-06-23 17:16:54.219715056 +0300 @@ -108,8 +108,8 @@ { "e200z4", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE| PPC_OPCODE_SPE | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI - | PPC_OPCODE_E500 | PPC_OPCODE_E200Z4), - PPC_OPCODE_VLE }, + | PPC_OPCODE_E500 | PPC_OPCODE_E200Z4 | PPC_OPCODE_VLE), + 0 }, { "e300", PPC_OPCODE_PPC | PPC_OPCODE_E300, 0 }, { "e500", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE @@ -235,12 +235,13 @@ dialect = POWERPC_DIALECT (info); /* Disassemble according to the section headers flags for VLE-mode. */ - if (dialect & PPC_OPCODE_VLE - && info->section != NULL && info->section->owner != NULL + if (dialect & PPC_OPCODE_VLE) + return dialect; + else if (info->section != NULL && info->section->owner != NULL && bfd_get_flavour (info->section->owner) == bfd_target_elf_flavour && elf_object_id (info->section->owner) == PPC32_ELF_DATA && (elf_section_flags (info->section) & SHF_PPC_VLE) != 0) - return dialect; + return PPC_OPCODE_VLE; else return dialect & ~ PPC_OPCODE_VLE; }