[binutils-gdb] x86 disassembler: Add -Mannotate option to display symbolic names associated with immediates

Nick Clifton nickc@sourceware.org
Fri Apr 24 13:35:33 GMT 2026


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=a9450872773511b5c527cf68598a2381a4a03fca

commit a9450872773511b5c527cf68598a2381a4a03fca
Author: Nick Clifton <nickc@redhat.com>
Date:   Fri Apr 24 14:34:50 2026 +0100

    x86 disassembler: Add -Mannotate option to display symbolic names associated with immediates

Diff:
---
 binutils/NEWS                                     |  4 ++
 binutils/doc/binutils.texi                        |  6 ++
 binutils/testsuite/binutils-all/x86-64/x86-64.exp | 31 +++++++++++
 opcodes/i386-dis.c                                | 68 +++++++++++++++++++++++
 4 files changed, 109 insertions(+)

diff --git a/binutils/NEWS b/binutils/NEWS
index 5ac0e8b7811..29821c96d0f 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -1,5 +1,9 @@
 -*- text -*-
 
+* The x86 and x86_64 disassemblers now accept a command line option of
+  "-M annotate-immediates" which displays the symbol associated with immediate
+  values, should there be one.
+  
 * Objdump and readelf now have a --debug-dir=<DIR> option which can be used to
   tell them where to find separate debug info files.
 
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index 59ffe548543..45df92394b6 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -2729,6 +2729,12 @@ When in AT&T mode and also for a limited set of instructions when in Intel
 mode, instructs the disassembler to print a mnemonic suffix even when the
 suffix could be inferred by the operands or, for certain instructions, the
 execution mode's defaults.
+
+@item annotate-immediates
+Display the symbol associated with immediate values, should there be
+one.  Only works on executable binaries and shared libraries, not
+static object files.
+
 @end table
 
 For PowerPC, the @option{-M} argument @option{raw} selects
diff --git a/binutils/testsuite/binutils-all/x86-64/x86-64.exp b/binutils/testsuite/binutils-all/x86-64/x86-64.exp
index 162030e5aea..49ade490fb7 100644
--- a/binutils/testsuite/binutils-all/x86-64/x86-64.exp
+++ b/binutils/testsuite/binutils-all/x86-64/x86-64.exp
@@ -323,3 +323,34 @@ if {[catch "system \"bzip2 -dc $t > $obj\""] != 0} {
     run_pr33230_test "$testname" $obj "" $run_readelf
     run_pr33230_test "$testname" $obj "--input-target=default" $run_readelf
 }
+
+# Test objdump -M annotate
+
+proc test_objdump_M_annotate { } {
+    global srcdir
+    global subdir
+    global OBJDUMP
+    global OBJDUMPFLAGS
+    global exe
+
+    set test "objdump -M annotate"
+
+    if { [target_compile $srcdir/$subdir/../testprog.c tmpdir/testprog${exe} executable debug] != "" } {
+	unsupported "$test (build)"
+	return
+    }
+
+    set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS -d -M annotate tmpdir/testprog${exe}"]
+
+    # Look for something like this in the disassembly:
+    #   400419: bf 18 30 40 00   mov $0x403018,%edi  #  [common]
+    set want " \[common\]"
+
+    if [regexp $want $got] then {
+	pass $test
+    } else {
+	fail $test
+    }
+}
+
+test_objdump_M_annotate
diff --git a/opcodes/i386-dis.c b/opcodes/i386-dis.c
index 21f37bc7509..f0749c1fad0 100644
--- a/opcodes/i386-dis.c
+++ b/opcodes/i386-dis.c
@@ -41,6 +41,8 @@
 
 typedef struct instr_info instr_info;
 
+static bool annotate_immediates = false;
+
 static bool dofloat (instr_info *, int);
 static int putop (instr_info *, const char *, int);
 static void oappend_with_style (instr_info *, const char *,
@@ -121,6 +123,9 @@ static void ATTRIBUTE_PRINTF_3 i386_dis_printf (const disassemble_info *,
 /* The maximum operand buffer size.  */
 #define MAX_OPERAND_BUFFER_SIZE 128
 
+/* The comment buffer size.  */
+#define COMMENT_BUFFER_SIZE 128
+
 enum address_mode
 {
   mode_16bit,
@@ -176,6 +181,8 @@ struct instr_info
 
   char obuf[MAX_OPERAND_BUFFER_SIZE];
   char *obufp;
+  char cbuf[COMMENT_BUFFER_SIZE];
+  char * cbufp;
   char *mnemonicendp;
   const uint8_t *start_codep;
   uint8_t *codep;
@@ -9043,6 +9050,7 @@ with the -M switch (multiple options should be separated by commas):\n"));
   fprintf (stream, _("  suffix      Always display instruction suffix in AT&T syntax\n"));
   fprintf (stream, _("  amd64       Display instruction in AMD64 ISA\n"));
   fprintf (stream, _("  intel64     Display instruction in Intel64 ISA\n"));
+  fprintf (stream, _("  annotate-immediates  Annotate immediate operands that match symbols\n"));
 }
 
 /* Bad opcode.  */
@@ -9741,6 +9749,7 @@ print_insn (bfd_vma pc, disassemble_info *info, int intel_syntax)
     .start_codep = priv.the_buffer,
     .codep = priv.the_buffer,
     .obufp = ins.obuf,
+    .cbufp = ins.cbuf,
     .last_lock_prefix = -1,
     .last_repz_prefix = -1,
     .last_repnz_prefix = -1,
@@ -9825,6 +9834,9 @@ print_insn (bfd_vma pc, disassemble_info *info, int intel_syntax)
       else if (startswith (p, "suffix"))
 	priv.orig_sizeflag |= SUFFIX_ALWAYS;
 
+      else if (startswith (p, "annotate"))
+	annotate_immediates = true;
+
       p = strchr (p, ',');
       if (p != NULL)
 	p++;
@@ -10363,6 +10375,13 @@ print_insn (bfd_vma pc, disassemble_info *info, int intel_syntax)
 	  info);
 	break;
       }
+  if (ins.cbufp != ins.cbuf)
+    {
+      if (i == MAX_OPERANDS)
+	i386_dis_printf (info, dis_style_comment_start, "        # ");
+      i386_dis_printf (info, dis_style_comment_start, "%s", ins.cbuf);
+    }
+  
   ret = ins.codep - priv.the_buffer;
  out:
   info->private_data = NULL;
@@ -11564,6 +11583,26 @@ oappend_with_style (instr_info *ins, const char *s,
   ins->obufp = stpcpy (ins->obufp, s);
 }
 
+/* Add a comment to the comment buffer.  */
+
+static void
+cappend_with_style (instr_info *ins, const char *s,
+		    enum disassembler_style style)
+{
+  if (ins->cbufp + strlen (s) + 4 >= ins->cbuf + COMMENT_BUFFER_SIZE)
+    return;
+
+  unsigned num = (unsigned) style;
+
+  *ins->cbufp++ = STYLE_MARKER_CHAR;
+  *ins->cbufp++ = (num < 10 ? ('0' + num)
+		   : ((num < 16) ? ('a' + (num - 10)) : '0'));
+  *ins->cbufp++ = STYLE_MARKER_CHAR;
+  *ins->cbufp = '\0';
+
+  ins->cbufp = stpcpy (ins->cbufp, s);
+}
+
 /* Add a single character C to the buffer pointer to by INS->obufp, marking
    the style for the character as STYLE.  */
 
@@ -11637,7 +11676,36 @@ oappend_immediate (instr_info *ins, bfd_vma imm)
 {
   if (!ins->intel_syntax)
     oappend_char_with_style (ins, '$', dis_style_immediate);
+
   print_operand_value (ins, imm, dis_style_immediate);
+
+  /* Determine if we can display some more information about this immediate.  */
+  if (! annotate_immediates
+      /* Don't bother with zero, even if there is symbol associated with it.  */
+      || imm == 0
+      /* For the next tests we need a BFD.  If we do not have one then do not proceed.  */
+      || ins->info->section == NULL
+      || ins->info->section->owner == NULL
+      /* Save time by avoiding immediates that cannot reference part of the address space.  */
+      || imm < ins->info->section->owner->start_address
+      /* Also skip static object files as their symbols have not been resolved.  */
+      || (ins->info->section->owner->flags & (EXEC_P | DYNAMIC)) == 0)
+    return;
+
+  asymbol * sym = ins->info->symbol_at_address_func (imm, ins->info);
+  if (sym == NULL)
+    return;
+
+  char * annotation = NULL;
+
+  /* FIXME: Potential memory leak: strictly speaking asprintf()
+     can return 0 whilst also having allocated some memory.  */
+  if (asprintf (& annotation, " [%s]", sym->name) > 0)
+    {
+      /* Display the symbol associated with address 'imm'.  */
+      cappend_with_style (ins, annotation, dis_style_symbol);
+      free (annotation);
+    }
 }
 
 /* Put DISP in BUF as signed hex number.  */


More information about the Binutils-cvs mailing list