¿Cómo desmontar una sola función usando objdump?
Tengo un binario instalado en mi sistema, y me gustaría ver el desmontaje de una función dada. Preferiblemente usando objdump
, pero otras soluciones también serían aceptables.
De estas preguntas He aprendido que podría ser capaz de desensamblar parte del código si solo conozco las direcciones de límite. De esta respuesta he aprendido cómo convertir mis símbolos de depuración dividida en un solo archivo.
Pero incluso operando en ese solo archivo, e incluso desensamblando todo el código (es decir, sin dirección de inicio o parada, pero sin parámetro -d
a objdump
), todavía no veo ese símbolo en ninguna parte. Lo que tiene sentido en la medida en que la función en cuestión es estática, por lo que no se exporta. Sin embargo, valgrind
reportará el nombre de la función, por lo que debe almacenarse en algún lugar.
Mirando los detalles de las secciones de depuración, encuentro ese nombre mencionado en la sección .debug_str
, pero no conozco una herramienta que pueda convertir esto en un rango de direcciones.
6 answers
Sugeriría usar gdb como el enfoque más simple. Incluso puedes hacerlo como un solo trazador de líneas, como:
gdb -batch -ex 'file /bin/ls' -ex 'disassemble main'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-01 01:47:57
Gdb disassemble/rs
para mostrar también los bytes fuente y raw
Con este formato, se acerca mucho a la salida objdump -S
:
gdb -batch -ex "file $EXECUTABLE" -ex "disassemble/rs $FUNCTION"
A. c: {[16]]}
#include <assert.h>
int myfunc(int i) {
i = i + 2;
i = i * 2;
return i;
}
int main(void) {
assert(myfunc(1) == 6);
assert(myfunc(2) == 8);
return 0;
}
Compilar y desensamblar
gcc -std=c99 -O0 -g a.c
gdb -batch -ex 'file a.out' -ex "disassemble/rs myfunc"
Desmontaje:
Dump of assembler code for function main:
a.c:
1 int main(void) {
0x00000000004004d6 <+0>: 55 push %rbp
0x00000000004004d7 <+1>: 48 89 e5 mov %rsp,%rbp
2 int i;
3 i = 0;
0x00000000004004da <+4>: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
4 i = i + 2;
0x00000000004004e1 <+11>: 83 45 fc 02 addl $0x2,-0x4(%rbp)
5 i = i * 2;
0x00000000004004e5 <+15>: d1 65 fc shll -0x4(%rbp)
6 return 0;
0x00000000004004e8 <+18>: b8 00 00 00 00 mov $0x0,%eax
7 }
0x00000000004004ed <+23>: 5d pop %rbp
0x00000000004004ee <+24>: c3 retq
End of assembler dump.
Probado en Ubuntu 16.04, GDB 7.11.1.
Soluciones de Objdump + awk
Imprimir el párrafo mencionado en: https://unix.stackexchange.com/questions/82944/how-to-grep-for-text-in-a-file-and-display-the-paragraph-that-has-the-text
objdump -d a.out | awk -v RS= '/^[[:xdigit:]]+ <FUNCTION>/'
Por ejemplo:
objdump -d a.out | awk -v RS= '/^[[:xdigit:]]+ <myfunc>/'
Da solo:
000000000000064a <myfunc>:
64a: 55 push %rbp
64b: 48 89 e5 mov %rsp,%rbp
64e: 89 7d fc mov %edi,-0x4(%rbp)
651: 83 45 fc 02 addl $0x2,-0x4(%rbp)
655: d1 65 fc shll -0x4(%rbp)
658: 8b 45 fc mov -0x4(%rbp),%eax
65b: 5d pop %rbp
65c: c3 retq
Cuando se usa -S
, no creo que haya una forma a prueba de fallos, ya que los comentarios de código podrían contener cualquier secuencia posible... Pero lo siguiente funciona casi todo el tiempo:
objdump -S a.out | awk '/^[[:xdigit:]]+ <FUNCTION>:$/{flag=1;next}/^[[:xdigit:]]+ <.*>:$/{flag=0}flag'
Adaptado de: Cómo seleccionar líneas entre dos patrones de marcadores que pueden ocurrir varias veces con awk / sed
Respuestas de la lista de correo
Hay un hilo de 2010 en la lista de correo que dice que no es posible: https://sourceware.org/ml/binutils/2010-04/msg00445.html
Además de la solución gdb
propuesta por Tom, también comentan otra (peor) solución de compilar con -ffunction-section
que pone una función por sección y luego descarga la sección.
Nicolas Clifton le dio un WONTFIX https://sourceware.org/ml/binutils/2015-07/msg00004.html , probablemente porque la solución del GDB cubre ese caso de uso.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-04 16:09:05
Desmontar Una Sola Función usando Objdump
Tengo dos soluciones:
1. Basado en Línea de comandos
Este método funciona perfectamente y también es muy corto. Yo uso objdump con -d opción y tubería que a awk. La salida desmontada se ve como
000000000000068a <main>:
68a: 55 push %rbp
68b: 48 89 e5 mov %rsp,%rbp
68e: 48 83 ec 20 sub $0x20,%rsp
A section or function is separated by an empty line. Por lo tanto, cambiando el FS (Separador de campo) a nueva línea y el RS (Seperator Registro) a dos veces nueva línea le permiten buscar fácilmente para su función recomendada, ya que es simplemente para encontrar dentro del campo $1!
objdump -d name_of_your_obj_file | awk -F"\n" -v RS="\n\n" '$1 ~ /main/'
Por supuesto, puede reemplazar main a cualquier función que desee que sea de salida.
2. Bash Script
He escrito un pequeño script bash para este número. Simplemente cópielo y guárdelo como, por ejemplo, dasm archivo.
#!/bin/bash
# Author: abu
# Description: puts disassembled objectfile to std-out
if [ $# = 2 ]; then
sstrg="^[[:xdigit:]]{2,}+.*<$2>:$"
objdump -d $1 | awk -F"\n" -v RS="\n\n" '$1 ~ /'"$sstrg"'/'
elif [ $# = 1 ]; then
objdump -d $1 | awk -F"\n" -v RS="\n\n" '{ print $1 }'
else
echo "You have to add argument(s)"
echo "Usage: "$0 " arg1 arg2"
echo "Description: print disassembled label to std-out"
echo " arg1: name of object file"
echo " arg2: name of function to be disassembled"
echo " "$0 " arg1 ... print labels and their rel. addresses"
fi
Cambiar el x-access e invocarlo con por ejemplo:
chmod +x dasm
./dasm test main
Esto es mucho más rápido que invocar gdb con un script. Al lado de la forma de usar objdump no cargar las bibliotecas en la memoria y por lo tanto es más seguro!
Vitaly Fadeev programó el autocompletado a este script, que es realmente una característica agradable y acelera la escritura.
El script se puede encontrar aquí.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-29 20:21:52
Esto funciona igual que la solución gdb (en el sentido de que desplaza las compensaciones hacia cero), excepto que no está rezagado (hace el trabajo en aproximadamente 5ms en mi PC, mientras que la solución gdb tarda alrededor de 150ms):
Objdump_func:
#!/bin/sh
# $1 -- function name; rest -- object files
fn=$1; shift 1
exec objdump -d "$@" |
awk " /^[[:xdigit:]].*<$fn>/,/^\$/ { print \$0 }" |
awk -F: -F' ' 'NR==1 { offset=strtonum("0x"$1); print $0; }
NR!=1 { split($0,a,":"); rhs=a[2]; n=strtonum("0x"$1); $1=sprintf("%x", n-offset); printf "%4s:%s\n", $1,rhs }'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-07 16:23:42
Para simplificar el uso de awk para analizar la salida de objdump en relación con otras respuestas:
objdump -d filename | sed '/<functionName>:/,/^$/!d'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-01 04:23:27
Finalización de Bash para ./dasm
Nombre completo de los símbolos a esta solución (versión D lang):
- Escribiendo
dasm test
y luego presionando la pestaña Tab , obtendrá una lista de todas las funciones. - Escribiendo
dasm test m
y luego presionando la pestaña Tab se mostrarán todas las funciones que comiencen con m, o en caso de que solo exista una función, se completará automáticamente.
Archivo /etc/bash_completion.d/dasm
:
# bash completion for dasm
_dasm()
{
local cur=${COMP_WORDS[COMP_CWORD]}
if [[ $COMP_CWORD -eq 1 ]] ; then
# files
COMPREPLY=( $( command ls *.o -F 2>/dev/null | grep "^$cur" ) )
elif [[ $COMP_CWORD -eq 2 ]] ; then
# functions
OBJFILE=${COMP_WORDS[COMP_CWORD-1]}
COMPREPLY=( $( command nm --demangle=dlang $OBJFILE | grep " W " | cut -d " " -f 3 | tr "()" " " | grep "$cur" ) )
else
COMPREPLY=($(compgen -W "" -- "$cur"));
fi
}
complete -F _dasm dasm
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-28 13:42:05