MIPS/GCC: Mark text contents as code or data
diff mbox

Message ID alpine.DEB.2.20.17.1611081807350.10580@tp.orcam.me.uk
State Accepted
Headers show

Commit Message

Maciej W. Rozycki Nov. 11, 2016, 5:05 p.m. UTC
Add local symbols of the correct type at the beginning and the end of 
inline jump tables and MIPS16 constant pools, marking these data areas
as such while keeping code outside marked as such as well.

Consider the following example, built as MIPS16 code:

$ cat switch16.c
int
foo (int i)
{
  static int j;

  j += i;
  switch (i)
    {
    case -5:
      return -2;
    case -3:
      return -1;
    case 0:
      return 0;
    case 3:
      return 1;
    case 5:
      return 2;
    default:
      break;
    }
  return j;
}
$ gcc -mips16 -O2 -S switch16.c -o switch16-0.s
$ cat switch16-0.s
	.file	1 "switch16.c"
	.section .mdebug.abi32
	.previous
	.nan	legacy
	.module	fp=xx
	.module	nooddspreg
	.abicalls
	.option	pic0
	.text
	.align	2
	.globl	foo
	.set	mips16
	.set	nomicromips
	.ent	foo
	.type	foo, @function
foo:
	.frame	$sp,0,$31		# vars= 0, regs= 0/0, args= 0, gp= 0
	.mask	0x00000000,0
	.fmask	0x00000000,0
	lw	$3,$L11
	lw	$2,0($3)
	addu	$2,$4,$2
	sw	$2,0($3)
	addiu	$3,$4,5
	sltu	$3, 11
	bteqz	$L1
	sll	$5, $3, 1
	la	$3, $L4
	addu	$5, $3, $5
	lh	$5, 0($5)
	addu	$3, $3, $5
	j	$3
	.align	1
	.align	2
$L4:
	.half	$L9-$L4
	.half	$L1-$L4
	.half	$L5-$L4
	.half	$L1-$L4
	.half	$L1-$L4
	.half	$L6-$L4
	.half	$L1-$L4
	.half	$L1-$L4
	.half	$L7-$L4
	.half	$L1-$L4
	.half	$L8-$L4
$L9:
	li	$2,2
	neg	$2,$2
$L1:
	jr	$31
$L5:
	li	$2,1
	.set	noreorder
	.set	nomacro
	jr	$31
	neg	$2,$2
	.set	macro
	.set	reorder

$L6:
	.set	noreorder
	.set	nomacro
	jr	$31
	move	$2,$4
	.set	macro
	.set	reorder

$L7:
	.set	noreorder
	.set	nomacro
	jr	$31
	li	$2,1
	.set	macro
	.set	reorder

$L8:
	.set	noreorder
	.set	nomacro
	jr	$31
	li	$2,2
	.set	macro
	.set	reorder

	.align	2
$L11:
	.word	j.1474
	.end	foo
	.size	foo, .-foo
	.local	j.1474
	.comm	j.1474,4,4
	.ident	"GCC: (GNU) 7.0.0 20160810 (experimental)"
$ as -o switch16-0.o switch16-0.s
$ readelf -s switch16-0.o

Symbol table '.symtab' contains 13 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS switch16.c
     2: 00000000     0 SECTION LOCAL  DEFAULT    1 
     3: 00000000     0 SECTION LOCAL  DEFAULT    3 
     4: 00000000     0 SECTION LOCAL  DEFAULT    4 
     5: 00000000     0 SECTION LOCAL  DEFAULT    9 
     6: 00000000     4 OBJECT  LOCAL  DEFAULT    4 j.1474
     7: 00000000     0 SECTION LOCAL  DEFAULT    5 
     8: 00000000     0 SECTION LOCAL  DEFAULT    6 
     9: 00000000     0 SECTION LOCAL  DEFAULT    7 
    10: 00000000     0 SECTION LOCAL  DEFAULT   10 
    11: 00000000     0 SECTION LOCAL  DEFAULT   11 
    12: 00000000    80 FUNC    GLOBAL DEFAULT [MIPS16]     1 foo
$ objdump -dr switch16-0.o

switch16-0.o:     file format elf32-tradbigmips


Disassembly of section .text:

00000000 <foo>:
   0:	b313      	lw	v1,4c <foo+0x4c>
   2:	9b40      	lw	v0,0(v1)
   4:	e449      	addu	v0,a0,v0
   6:	db40      	sw	v0,0(v1)
   8:	4465      	addiu	v1,a0,5
   a:	5b0b      	sltiu	v1,11
   c:	6014      	bteqz	36 <foo+0x36>
   e:	3564      	sll	a1,v1,1
  10:	0b03      	la	v1,1c <foo+0x1c>
  12:	e3b5      	addu	a1,v1,a1
  14:	8da0      	lh	a1,0(a1)
  16:	e3ad      	addu	v1,a1
  18:	eb80      	jrc	v1
  1a:	6500      	nop
  1c:	0017      	addiu	s0,sp,92
  1e:	001b      	addiu	s0,sp,108
  20:	001d      	addiu	s0,sp,116
  22:	001b      	addiu	s0,sp,108
  24:	001b      	addiu	s0,sp,108
  26:	0023      	addiu	s0,sp,140
  28:	001b      	addiu	s0,sp,108
  2a:	001b      	addiu	s0,sp,108
  2c:	0027      	addiu	s0,sp,156
  2e:	001b      	addiu	s0,sp,108
  30:	002b      	addiu	s0,sp,172
  32:	6a02      	li	v0,2
  34:	ea4b      	neg	v0
  36:	e8a0      	jrc	ra
  38:	6a01      	li	v0,1
  3a:	e820      	jr	ra
  3c:	ea4b      	neg	v0
  3e:	e820      	jr	ra
  40:	6744      	move	v0,a0
  42:	e820      	jr	ra
  44:	6a01      	li	v0,1
  46:	e820      	jr	ra
  48:	6a02      	li	v0,2
  4a:	6500      	nop
  4c:	0000      	addiu	s0,sp,0
			4c: R_MIPS_32	.bss
	...
$ 

As you can see the assembly source generated has code interspersed with 
data, all within the span of the `foo' function definition, and 
consequently all the binary contents of the function in the object file 
produced are interpreted as instructions by the disassembler.

Now with appropriate markers added we get these results instead:

$ gcc -mips16 -O2 -S switch16.c -o switch16-1.s
$ cat switch16-1.s
	.file	1 "switch16.c"
	.section .mdebug.abi32
	.previous
	.nan	legacy
	.module	fp=xx
	.module	nooddspreg
	.abicalls
	.option	pic0
	.text
	.align	2
	.globl	foo
	.set	mips16
	.set	nomicromips
	.ent	foo
	.type	foo, @function
foo:
	.frame	$sp,0,$31		# vars= 0, regs= 0/0, args= 0, gp= 0
	.mask	0x00000000,0
	.fmask	0x00000000,0
	lw	$3,$L11
	lw	$2,0($3)
	addu	$2,$4,$2
	sw	$2,0($3)
	addiu	$3,$4,5
	sltu	$3, 11
	bteqz	$L1
	sll	$5, $3, 1
	la	$3, $L4
	addu	$5, $3, $5
	lh	$5, 0($5)
	addu	$3, $3, $5
	j	$3
	.align	1
	.align	2
	.type	__jump_foo_4, @object
__jump_foo_4:
$L4:
	.half	$L9-$L4
	.half	$L1-$L4
	.half	$L5-$L4
	.half	$L1-$L4
	.half	$L1-$L4
	.half	$L6-$L4
	.half	$L1-$L4
	.half	$L1-$L4
	.half	$L7-$L4
	.half	$L1-$L4
	.half	$L8-$L4
	.type	__jend_foo_4, @function
__jend_foo_4:
	.insn
$L9:
	li	$2,2
	neg	$2,$2
$L1:
	jr	$31
$L5:
	li	$2,1
	.set	noreorder
	.set	nomacro
	jr	$31
	neg	$2,$2
	.set	macro
	.set	reorder

$L6:
	.set	noreorder
	.set	nomacro
	jr	$31
	move	$2,$4
	.set	macro
	.set	reorder

$L7:
	.set	noreorder
	.set	nomacro
	jr	$31
	li	$2,1
	.set	macro
	.set	reorder

$L8:
	.set	noreorder
	.set	nomacro
	jr	$31
	li	$2,2
	.set	macro
	.set	reorder

	.type	__pool_foo_11, @object
__pool_foo_11:
	.align	2
$L11:
	.word	j.1474
	.type	__pend_foo_11, @function
__pend_foo_11:
	.insn
	.end	foo
	.size	foo, .-foo
	.local	j.1474
	.comm	j.1474,4,4
	.ident	"GCC: (GNU) 7.0.0 20160810 (experimental)"
$ as -o switch16-1.o switch16-1.s
$ readelf -s switch16-1.o

Symbol table '.symtab' contains 17 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS switch16.c
     2: 00000000     0 SECTION LOCAL  DEFAULT    1 
     3: 00000000     0 SECTION LOCAL  DEFAULT    3 
     4: 00000000     0 SECTION LOCAL  DEFAULT    4 
     5: 00000000     0 SECTION LOCAL  DEFAULT    9 
     6: 0000001c     0 OBJECT  LOCAL  DEFAULT    1 __jump_foo_4
     7: 00000032     0 FUNC    LOCAL  DEFAULT [MIPS16]     1 __jend_foo_4
     8: 0000004c     0 OBJECT  LOCAL  DEFAULT    1 __pool_foo_11
     9: 00000000     4 OBJECT  LOCAL  DEFAULT    4 j.1474
    10: 00000050     0 FUNC    LOCAL  DEFAULT [MIPS16]     1 __pend_foo_11
    11: 00000000     0 SECTION LOCAL  DEFAULT    5 
    12: 00000000     0 SECTION LOCAL  DEFAULT    6 
    13: 00000000     0 SECTION LOCAL  DEFAULT    7 
    14: 00000000     0 SECTION LOCAL  DEFAULT   10 
    15: 00000000     0 SECTION LOCAL  DEFAULT   11 
    16: 00000000    80 FUNC    GLOBAL DEFAULT [MIPS16]     1 foo
$ objdump -dr switch16-1.o

switch16-1.o:     file format elf32-tradbigmips


Disassembly of section .text:

00000000 <foo>:
   0:	b313      	lw	v1,4c <__pool_foo_11>
   2:	9b40      	lw	v0,0(v1)
   4:	e449      	addu	v0,a0,v0
   6:	db40      	sw	v0,0(v1)
   8:	4465      	addiu	v1,a0,5
   a:	5b0b      	sltiu	v1,11
   c:	6014      	bteqz	36 <__jend_foo_4+0x4>
   e:	3564      	sll	a1,v1,1
  10:	0b03      	la	v1,1c <__jump_foo_4>
  12:	e3b5      	addu	a1,v1,a1
  14:	8da0      	lh	a1,0(a1)
  16:	e3ad      	addu	v1,a1
  18:	eb80      	jrc	v1
  1a:	6500      	nop

0000001c <__jump_foo_4>:
  1c:	0017 001b 001d 001b 001b 0023 001b 001b     ...........#....
  2c:	0027 001b 002b                              .'...+

00000032 <__jend_foo_4>:
  32:	6a02      	li	v0,2
  34:	ea4b      	neg	v0
  36:	e8a0      	jrc	ra
  38:	6a01      	li	v0,1
  3a:	e820      	jr	ra
  3c:	ea4b      	neg	v0
  3e:	e820      	jr	ra
  40:	6744      	move	v0,a0
  42:	e820      	jr	ra
  44:	6a01      	li	v0,1
  46:	e820      	jr	ra
  48:	6a02      	li	v0,2
  4a:	6500      	nop

0000004c <__pool_foo_11>:
  4c:	0000 0000                                   ....
			4c: R_MIPS_32	.bss
$ 

Now we have an `__jump_foo_4' and `__pool_foo_11' symbols marking the 
beginning of data and corresponding `__jend_foo_4' and `__pend_foo_11' 
symbols marking the end of data.  The type of these symbols, either
`object' or `function' is what drives the dissasembler and makes it
interpret binary contents as data or code respectively.

Internally we track the beginning and the end of MIPS16 constant pools 
with the use of dummy `consttable' and `consttable_end' insns, which are 
inserted at the beginning and the end of each pool created.  As there 
can be multiple pools within one function, these insns carry the number, 
which is guaranteed to be unique across the whole compilation unit, of 
the first local label within the pool, used to refer to its first 
element.

This number is then used, along with the name of the containing 
function, and fixed `__pool_' and `__pend_' prefixes, to construct 
unique local symbols, which are output in `mips_final_prescan_insn' and 
`mips_final_postscan_insn' as assembly code is produced for the insn.  
There is a `.insn' pseudo-op included in the assembly generated for the 
ending symbol so that the ISA mode is also correctly recorded for the 
disassembly of any padding following if there are no further actual 
instructions after the pool.

For jump tables we already have hooks provided by the middle end so we 
use them instead and don't have to produce any extra insns.  The 
middle-end hooks are ASM_OUTPUT_CASE_LABEL and ASM_OUTPUT_CASE_END, 
although in the former case we use the ASM_OUTPUT_BEFORE_CASE_LABEL 
helper macro used by `config/elfos.h' instead.  We can only set the 
symbol type for ELF targets, so the use of this helper macro is 
appropriate and avoids the problem of changing the behaviour with 
respect to jump table alignment for targets which do not use 
`config/elfos.h' as we now have ASM_OUTPUT_ALIGN carried over from there 
to the target-wide `config/mips/mips.h' header.  By using 
ASM_OUTPUT_BEFORE_CASE_LABEL which is only referred by `config/elfos.h' 
we avoid this problem.

As with MIPS16 constant pools there can be multiple jump tables within 
one function so again we take a unique number of the jump table label, 
already provided as an argument to ASM_OUTPUT_BEFORE_CASE_LABEL and 
ASM_OUTPUT_CASE_END, and we join it with the name of the containing 
function and fixed `__jump_' and `__jend_' prefixes, ensuring this way 
that local symbols constructed this way are unique.  Like with the pools 
a `.insn' pseudo-op is included with the ending symbol in case no 
further actual code follows.

Finally the names of the prefixes have been chosen to mimic ones already 
used for the various MIPS16 floating-point stubs, therefore keeping the
naming convention consistent.

	gcc/
	* config/mips/mips-protos.h (mips_set_text_contents_type): New
	prototype.
	* config/mips/mips.h (ASM_OUTPUT_BEFORE_CASE_LABEL): New macro.
	(ASM_OUTPUT_CASE_END): Likewise.
	* config/mips/mips.c (mips_set_text_contents_type): New 
	function.
	(mips16_emit_constants): Record the pool's initial label number
	with the `consttable' insn.  Emit a `consttable_end' insn at the
	end.
	(mips_final_prescan_insn): Call `mips_set_text_contents_type'
	for `consttable' insns.
	(mips_final_postscan_insn): Call `mips_set_text_contents_type'
	for `consttable_end' insns.
	* config/mips/mips.md (unspec): Add UNSPEC_CONSTTABLE_END enum
	value.
	(consttable): Add operand.
	(consttable_end): New insn.

	gcc/testsuite/
	* gcc.target/mips/data-sym-jump.c: New test case.
	* gcc.target/mips/data-sym-pool.c: New test case.
	* gcc.target/mips/insn-pseudo-4.c: Adjust for constant pool 
	annotation.
---
 There is a slight assymetry between ASM_OUTPUT_BEFORE_CASE_LABEL and 
ASM_OUTPUT_CASE_END in that with any configurations not using 
`config/elfos.h' `mips_set_text_contents_type' won't be called from 
ASM_OUTPUT_CASE_LABEL at all, whereas in the case of ASM_OUTPUT_CASE_END 
the function will be called although is expected to be empty as 
ASM_OUTPUT_TYPE_DIRECTIVE is expected not to be defined with such 
configurations.

 I suspect this slight imperfection in the arrangement of the 
configuration macros is not worth further effort though as the semantics 
for configurations not using `config/elfos.h' is expected to be right, 
with just an unnecessary dummy call to `mips_set_text_contents_type', 
while indeed we may not have any such configuration supported anymore 
anyway.

 I have successfully regression-tested it with the `mips-mti-linux-gnu'
target, with a big-endian o32 regular MIPS multilib and a little-endian
o32 MIPS16 multilib, with no regressions.

 OK to apply?

  Maciej

gcc-mips-data-sym.diff

Comments

Matthew Fortune Nov. 15, 2016, 4:23 p.m. UTC | #1
Maciej Rozycki <Maciej.Rozycki@imgtec.com> writes:
> 	gcc/
> 	* config/mips/mips-protos.h (mips_set_text_contents_type): New
> 	prototype.
> 	* config/mips/mips.h (ASM_OUTPUT_BEFORE_CASE_LABEL): New macro.
> 	(ASM_OUTPUT_CASE_END): Likewise.
> 	* config/mips/mips.c (mips_set_text_contents_type): New
> 	function.
> 	(mips16_emit_constants): Record the pool's initial label number
> 	with the `consttable' insn.  Emit a `consttable_end' insn at the
> 	end.
> 	(mips_final_prescan_insn): Call `mips_set_text_contents_type'
> 	for `consttable' insns.
> 	(mips_final_postscan_insn): Call `mips_set_text_contents_type'
> 	for `consttable_end' insns.
> 	* config/mips/mips.md (unspec): Add UNSPEC_CONSTTABLE_END enum
> 	value.
> 	(consttable): Add operand.
> 	(consttable_end): New insn.
> 
> 	gcc/testsuite/
> 	* gcc.target/mips/data-sym-jump.c: New test case.
> 	* gcc.target/mips/data-sym-pool.c: New test case.
> 	* gcc.target/mips/insn-pseudo-4.c: Adjust for constant pool
> 	annotation.

Thanks for working on this it is really useful functionality.

I'm a little concerned the expected output tests may be fragile over
time but let's wait and see.

OK to commit.

Thanks,
Matthew
Maciej W. Rozycki Nov. 16, 2016, 5:15 p.m. UTC | #2
On Tue, 15 Nov 2016, Matthew Fortune wrote:

> I'm a little concerned the expected output tests may be fragile over
> time but let's wait and see.

 Indeed, but I'd rather see false negatives than false positives or no 
coverage at all.  And I hope the pieces of expected assembly quoted will 
help telling any false negatives and actual regressions apart very easily.

> OK to commit.

 Applied now, thanks for your review.

  Maciej
Paul Hua March 14, 2018, 9:10 a.m. UTC | #3
I noticed that data-sym-pool.c fails on -O0 flags.

-O0 output :
-----------------cut----------------------
frob:
        .frame  $17,8,$31               # vars= 0, regs= 1/0, args= 0, gp= 0
        .mask   0x00020000,0
        .fmask  0x00000000,0
        addiu   $sp,-8
        sd      $17,0($sp)
        move    $17,$sp
        lw      $2,$L4
        move    $sp,$17
        ld      $17,0($sp)
        addiu   $sp,8
        jr      $31
        .type   __pool_frob_3, @object
__pool_frob_3:
        .align  2
$L3:
        .word   __gnu_local_gp
$L4:
        .word   305419896
        .type   __pend_frob_3, @function
__pend_frob_3:
        .insn
        .end    frob
        .size   frob, .-frob
        .ident  "GCC: (gcc trunk r258495 mips64el o32 n32 n64) 8.0.1
20180313 (experimental)"
-------------end----------------------------------------------

Is it expected ? maybe we should add skip-if  -O0 flags.

Paul Hua


On Thu, Nov 17, 2016 at 1:15 AM, Maciej W. Rozycki <macro@imgtec.com> wrote:
> On Tue, 15 Nov 2016, Matthew Fortune wrote:
>
>> I'm a little concerned the expected output tests may be fragile over
>> time but let's wait and see.
>
>  Indeed, but I'd rather see false negatives than false positives or no
> coverage at all.  And I hope the pieces of expected assembly quoted will
> help telling any false negatives and actual regressions apart very easily.
>
>> OK to commit.
>
>  Applied now, thanks for your review.
>
>   Maciej
Maciej W. Rozycki April 9, 2018, 11:40 a.m. UTC | #4
Hi Paul,

 Apologies for the delay in reply, my @imgtec.com address has since become 
defunct and I have only come across your e-mail in my ever-lagging routine 
mailing traffic review.

On Wed, 14 Mar 2018, Paul Hua wrote:

> I noticed that data-sym-pool.c fails on -O0 flags.
> 
> -O0 output :
> -----------------cut----------------------
> frob:
>         .frame  $17,8,$31               # vars= 0, regs= 1/0, args= 0, gp= 0
>         .mask   0x00020000,0
>         .fmask  0x00000000,0
>         addiu   $sp,-8
>         sd      $17,0($sp)
>         move    $17,$sp
>         lw      $2,$L4
>         move    $sp,$17
>         ld      $17,0($sp)
>         addiu   $sp,8
>         jr      $31
>         .type   __pool_frob_3, @object
> __pool_frob_3:
>         .align  2
> $L3:
>         .word   __gnu_local_gp
> $L4:
>         .word   305419896
>         .type   __pend_frob_3, @function
> __pend_frob_3:
>         .insn
>         .end    frob
>         .size   frob, .-frob
>         .ident  "GCC: (gcc trunk r258495 mips64el o32 n32 n64) 8.0.1
> 20180313 (experimental)"
> -------------end----------------------------------------------
> 
> Is it expected ? maybe we should add skip-if  -O0 flags.

 Thanks for your report.

 I think instead we should relax the matching pattern and also accept an 
arbitrary number of label-`.word' pairs ahead of and/or after the required 
one in the constant pool.  I'll post a fix.

  Maciej

Patch
diff mbox

Index: gcc/gcc/config/mips/mips-protos.h
===================================================================
--- gcc.orig/gcc/config/mips/mips-protos.h	2016-11-09 18:56:34.412202878 +0000
+++ gcc/gcc/config/mips/mips-protos.h	2016-11-09 18:57:01.571953223 +0000
@@ -271,6 +271,8 @@  extern void mips_declare_object (FILE *,
 				 const char *, ...) ATTRIBUTE_PRINTF_4;
 extern void mips_declare_object_name (FILE *, const char *, tree);
 extern void mips_finish_declare_object (FILE *, tree, int, int);
+extern void mips_set_text_contents_type (FILE *, const char *,
+					 unsigned long, bool);
 
 extern bool mips_small_data_pattern_p (rtx);
 extern rtx mips_rewrite_small_data (rtx);
Index: gcc/gcc/config/mips/mips.c
===================================================================
--- gcc.orig/gcc/config/mips/mips.c	2016-11-09 18:56:34.423849203 +0000
+++ gcc/gcc/config/mips/mips.c	2016-11-09 18:57:01.752162039 +0000
@@ -9742,6 +9742,37 @@  mips_finish_declare_object (FILE *stream
     }
 }
 #endif
+
+/* Mark text contents as code or data, mainly for the purpose of correct
+   disassembly.  Emit a local symbol and set its type appropriately for
+   that purpose.  Also emit `.insn' if marking contents as code so that
+   the ISA mode is recorded and any padding that follows is disassembled
+   as correct instructions.  */
+
+void
+mips_set_text_contents_type (FILE *file ATTRIBUTE_UNUSED,
+			     const char *prefix ATTRIBUTE_UNUSED,
+			     unsigned long num ATTRIBUTE_UNUSED,
+			     bool function_p ATTRIBUTE_UNUSED)
+{
+#ifdef ASM_OUTPUT_TYPE_DIRECTIVE
+  char buf[(sizeof (num) * 10) / 4 + 2];
+  const char *fnname;
+  char *sname;
+  rtx symbol;
+
+  sprintf (buf, "%lu", num);
+  symbol = XEXP (DECL_RTL (current_function_decl), 0);
+  fnname = targetm.strip_name_encoding (XSTR (symbol, 0));
+  sname = ACONCAT ((prefix, fnname, "_", buf, NULL));
+
+  ASM_OUTPUT_TYPE_DIRECTIVE (file, sname, function_p ? "function" : "object");
+  assemble_name (file, sname);
+  fputs (":\n", file);
+  if (function_p)
+    fputs ("\t.insn\n", file);
+#endif
+}
 
 /* Return the FOO in the name of the ".mdebug.FOO" section associated
    with the current ABI.  */
@@ -17124,17 +17155,22 @@  mips16_emit_constants_1 (machine_mode mo
   gcc_unreachable ();
 }
 
-/* Dump out the constants in CONSTANTS after INSN.  */
+/* Dump out the constants in CONSTANTS after INSN.  Record the initial
+   label number in the `consttable' and `consttable_end' insns emitted
+   at the beginning and the end of the constant pool respectively, so
+   that individual pools can be uniquely marked as data for the purpose
+   of disassembly.  */
 
 static void
 mips16_emit_constants (struct mips16_constant *constants, rtx_insn *insn)
 {
+  int label_num = constants ? CODE_LABEL_NUMBER (constants->label) : 0;
   struct mips16_constant *c, *next;
   int align;
 
   align = 0;
   if (constants)
-    insn = emit_insn_after (gen_consttable (), insn);
+    insn = emit_insn_after (gen_consttable (GEN_INT (label_num)), insn);
   for (c = constants; c != NULL; c = next)
     {
       /* If necessary, increase the alignment of PC.  */
@@ -17151,6 +17187,8 @@  mips16_emit_constants (struct mips16_con
       next = c->next;
       free (c);
     }
+  if (constants)
+    insn = emit_insn_after (gen_consttable_end (GEN_INT (label_num)), insn);
 
   emit_barrier_after (insn);
 }
@@ -20261,16 +20299,32 @@  mips_need_noat_wrapper_p (rtx_insn *insn
   return false;
 }
 
-/* Implement FINAL_PRESCAN_INSN.  */
+/* Implement FINAL_PRESCAN_INSN.  Mark MIPS16 inline constant pools
+   as data for the purpose of disassembly.  For simplicity embed the
+   pool's initial label number in the local symbol produced so that
+   multiple pools within a single function end up marked with unique
+   symbols.  The label number is carried by the `consttable' insn
+   emitted at the beginning of each pool.  */
 
 void
 mips_final_prescan_insn (rtx_insn *insn, rtx *opvec, int noperands)
 {
+  if (INSN_P (insn)
+      && GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE
+      && XINT (PATTERN (insn), 1) == UNSPEC_CONSTTABLE)
+    mips_set_text_contents_type (asm_out_file, "__pool_",
+				 XINT (XVECEXP (PATTERN (insn), 0, 0), 0),
+				 FALSE);
+
   if (mips_need_noat_wrapper_p (insn, opvec, noperands))
     mips_push_asm_switch (&mips_noat);
 }
 
-/* Implement TARGET_ASM_FINAL_POSTSCAN_INSN.  */
+/* Implement TARGET_ASM_FINAL_POSTSCAN_INSN.  Reset text marking to
+   code after a MIPS16 inline constant pool.  Like with the beginning
+   of a pool table use the pool's initial label number to keep symbols
+   unique.  The label number is carried by the `consttable_end' insn
+   emitted at the end of each pool.  */
 
 static void
 mips_final_postscan_insn (FILE *file ATTRIBUTE_UNUSED, rtx_insn *insn,
@@ -20278,6 +20332,13 @@  mips_final_postscan_insn (FILE *file ATT
 {
   if (mips_need_noat_wrapper_p (insn, opvec, noperands))
     mips_pop_asm_switch (&mips_noat);
+
+  if (INSN_P (insn)
+      && GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE
+      && XINT (PATTERN (insn), 1) == UNSPEC_CONSTTABLE_END)
+    mips_set_text_contents_type (asm_out_file, "__pend_",
+				 XINT (XVECEXP (PATTERN (insn), 0, 0), 0),
+				 TRUE);
 }
 
 /* Return the function that is used to expand the <u>mulsidi3 pattern.
Index: gcc/gcc/config/mips/mips.h
===================================================================
--- gcc.orig/gcc/config/mips/mips.h	2016-11-09 18:56:34.445992594 +0000
+++ gcc/gcc/config/mips/mips.h	2016-11-09 18:57:01.804444614 +0000
@@ -2986,6 +2986,32 @@  do {									\
 	     LOCAL_LABEL_PREFIX, VALUE);				\
 } while (0)
 
+/* Mark inline jump tables as data for the purpose of disassembly.  For
+   simplicity embed the jump table's label number in the local symbol
+   produced so that multiple jump tables within a single function end
+   up marked with unique symbols.  Retain the alignment setting from
+   `elfos.h' as we are replacing the definition from there.  */
+
+#undef ASM_OUTPUT_BEFORE_CASE_LABEL
+#define ASM_OUTPUT_BEFORE_CASE_LABEL(STREAM, PREFIX, NUM, TABLE)	\
+  do									\
+    {									\
+      ASM_OUTPUT_ALIGN ((STREAM), 2);					\
+      if (JUMP_TABLES_IN_TEXT_SECTION)					\
+	mips_set_text_contents_type (STREAM, "__jump_", NUM, FALSE);	\
+    }									\
+  while (0);
+
+/* Reset text marking to code after an inline jump table.  Like with
+   the beginning of a jump table use the label number to keep symbols
+   unique.  */
+
+#define ASM_OUTPUT_CASE_END(STREAM, NUM, TABLE)				\
+  do									\
+    if (JUMP_TABLES_IN_TEXT_SECTION)					\
+      mips_set_text_contents_type (STREAM, "__jend_", NUM, TRUE);	\
+  while (0);
+
 /* This is how to output an assembler line
    that says to advance the location counter
    to a multiple of 2**LOG bytes.  */
Index: gcc/gcc/config/mips/mips.md
===================================================================
--- gcc.orig/gcc/config/mips/mips.md	2016-11-09 18:56:34.458515411 +0000
+++ gcc/gcc/config/mips/mips.md	2016-11-09 20:54:38.794831645 +0000
@@ -121,6 +121,7 @@ 
   ;; MIPS16 constant pools.
   UNSPEC_ALIGN
   UNSPEC_CONSTTABLE
+  UNSPEC_CONSTTABLE_END
   UNSPEC_CONSTTABLE_INT
   UNSPEC_CONSTTABLE_FLOAT
 
@@ -7321,7 +7322,16 @@ 
 ;;
 
 (define_insn "consttable"
-  [(unspec_volatile [(const_int 0)] UNSPEC_CONSTTABLE)]
+  [(unspec_volatile [(match_operand 0 "const_int_operand" "")]
+		    UNSPEC_CONSTTABLE)]
+  ""
+  ""
+  [(set_attr "mode" "none")
+   (set_attr "insn_count" "0")])
+
+(define_insn "consttable_end"
+  [(unspec_volatile [(match_operand 0 "const_int_operand" "")]
+		    UNSPEC_CONSTTABLE_END)]
   ""
   ""
   [(set_attr "mode" "none")
Index: gcc/gcc/testsuite/gcc.target/mips/data-sym-jump.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.target/mips/data-sym-jump.c	2016-11-09 20:57:25.850097225 +0000
@@ -0,0 +1,50 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mips16 -mcode-readable=yes" } */
+/* { dg-skip-if "MIPS16 `casesi' loses at -Os" { *-*-* } { "-Os"} { "" } } */
+
+int
+frob (int i)
+{
+  switch (i)
+    {
+    case -5:
+      return -2;
+    case -3:
+      return -1;
+    case 0:
+      return 0;
+    case 3:
+      return 1;
+    case 5:
+      break;
+    default:
+      __builtin_unreachable ();
+    }
+  return i;
+}
+
+/* Expect assembly like:
+
+	la	$2, $L4
+						# Anything goes here.
+	.type	__jump_frob_4, @object		# Symbol # must match label.
+__jump_frob_4:					# The symbol must match.
+$L4:						# The label must match.
+	.half	$L3-$L4				# Or `.word'.  The subtrahend
+	.half	$L2-$L4				# label must match thoughout
+	.half	$L9-$L4				# (repeated 11 times).
+	.half	$L2-$L4				# .
+	.half	$L2-$L4				# .
+	.half	$L8-$L4				# .
+	.half	$L2-$L4				# .
+	.half	$L2-$L4				# .
+	.half	$L7-$L4				# .
+	.half	$L2-$L4				# .
+	.half	$L8-$L4				# .
+	.type	__jend_frob_4, @function	# Symbol # must match label.
+__jend_frob_4:					# The symbol must match.
+	.insn
+
+   that is `__jump_*'/`__jend_*' symbols inserted around a jump table.  */
+
+/* { dg-final { scan-assembler "\tla\t\\\$\[0-9\]+, (.L(\[0-9\]+))\n.*\t\\.type\t(__jump_frob_\\2), @object\n\\3:\n\\1:\n(?:\t\\.(?:half|word)\t.L\[0-9\]+-\\1\n)\{11\}\t\\.type\t(__jend_frob_\\2), @function\n\\4:\n\t\\.insn\n" } } */
Index: gcc/gcc/testsuite/gcc.target/mips/data-sym-pool.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.target/mips/data-sym-pool.c	2016-11-09 20:57:25.880515516 +0000
@@ -0,0 +1,25 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mips16 -mcode-readable=yes" } */
+
+int
+frob (void)
+{
+  return 0x12345678;
+}
+
+/* Expect assembly like:
+
+	lw	$2,$L3
+						# Anything goes here.
+	.type	__pool_frob_3, @object		# Symbol # must match label.
+__pool_frob_3:					# The symbol must match.
+	.align	2
+$L3:						# The label must match.
+	.word	305419896
+	.type	__pend_frob_3, @function	# Symbol # must match label.
+__pend_frob_3:					# The symbol must match.
+	.insn
+
+   that is `__pool_*'/`__pend_*' symbols inserted around a constant pool.  */
+
+/* { dg-final { scan-assembler "\tlw\t\\\$\[0-9\]+,(.L(\[0-9\]+))\n.*\t\\.type\t(__pool_frob_\\2), @object\n\\3:\n\t\\.align\t2\n\\1:\n\t\\.word\t305419896\n\t\\.type\t(__pend_frob_\\2), @function\n\\4:\n\t\\.insn\n" } } */
Index: gcc/gcc/testsuite/gcc.target/mips/insn-pseudo-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.target/mips/insn-pseudo-4.c	2016-11-09 20:57:21.901118536 +0000
+++ gcc/gcc/testsuite/gcc.target/mips/insn-pseudo-4.c	2016-11-09 20:57:25.890641344 +0000
@@ -18,10 +18,12 @@  unreachable (void)
 $L2:				# The label must match.
 	.insn
 $L3 = .				# It's there, but we don't care.
+	.type	__pool_unreachable_5, @object
+__pool_unreachable_5:
 	.align	2
 $L5:				# The label must match.
 	.word	305419896
 
    that is .insn to be inserted if a code label is at a constant pool.  */
 
-/* { dg-final { scan-assembler "\tlw\t(\\\$\[0-9\]+),(.L\[0-9\]+)\n.*\tbeqz\t\\1,(.L\[0-9\]+)\n.*\n\\3:\n\t\\.insn\n(?:.L\[0-9\]+ = \\.\n)?\t\\.align\t2\n\\2:\n\t\\.word\t305419896\n" } } */
+/* { dg-final { scan-assembler "\tlw\t(\\\$\[0-9\]+),(.L\[0-9\]+)\n.*\tbeqz\t\\1,(.L\[0-9\]+)\n.*\n\\3:\n\t\\.insn\n(?:.L\[0-9\]+ = \\.\n)?\t\\.type\t__pool_unreachable_\[0-9\]+, @object\n__pool_unreachable_\[0-9\]+:\n\t\\.align\t2\n\\2:\n\t\\.word\t305419896\n" } } */