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

Nick Clifton via Binutils-cvs <[email protected]>
Newsgroups gmane.comp.gnu.binutils.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=a9450872773511b5c527cf68598a2381a4a03fca

commit a9450872773511b5c527cf68598a2381a4a03fca
Author: Nick Clifton <[email protected]>
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.  */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.