elf - ¿Cómo desensamblar una sola función usando objdump?
debug-symbols disassembly (6)
Desarmar 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 la opción -d y lo canalizo a awk . La salida desensamblada se ve como
000000000000068a <main>:
68a: 55 push %rbp
68b: 48 89 e5 mov %rsp,%rbp
68e: 48 83 ec 20 sub $0x20,%rsp
Una sección o función está separada por una línea vacía. Por lo tanto, cambiar el FS (Seperador de campo) a la nueva línea y el RS (Separador de registros) a dos líneas nuevas le permite buscar fácilmente su función recomendada, ¡ya que es simplemente para encontrar dentro del campo de $ 1!
objdump -d name_of_your_obj_file | awk -F"/n" -v RS="/n/n" ''$1 ~ /main/''
Por supuesto, puede cambiar la función principal a cualquier función que desee.
2. Bash Script
He escrito un pequeño script bash para este tema. Simplemente cópielo y guárdelo como, por ejemplo, un archivo dasm .
#!/bin/bash
# Author: abu
# Description: puts disassembled objectfile to std-out
if [ $# = 2 ]; then
sstrg="^[[:xdigit:]]{2,}+.*<$2>:$"
objdump -d $1 | awk -v fun=$sstrg -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
Cambie el acceso x e invoqúelo con por ejemplo:
chmod +x dasm
./dasm test main
Esto es mucho más rápido que invocar gdb con un script. Además de usar objdump, ¡las bibliotecas no se cargarán en la memoria y, por lo tanto, serán más seguras!
Tengo un binario instalado en mi sistema y me gustaría ver el desmontaje de una función determinada. Preferiblemente usando objdump
, pero otras soluciones también serían aceptables.
De estas preguntas aprendí que podría desmontar parte del código si solo conozco las direcciones de los límites. A partir de esta respuesta , aprendí cómo convertir mis símbolos de depuración divididos en un único archivo.
Pero incluso operando en ese único archivo, e incluso desensamblando todo el código (es decir, sin inicio o detención de la dirección, sino con un parámetro -d
para objdump
), todavía no veo ese símbolo en ninguna parte. Lo cual 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
informará 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.
Completar Bash para ./dasm (ver respuesta arriba). Completar nombres de símbolos. (Versión D lang)
Archivos:
/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
Esto funciona igual que la solución gdb (en el sentido de que desplaza las compensaciones hacia cero), excepto que no es laggy (hace el trabajo en unos 5 ms en mi PC, mientras que la solución gdb tarda unos 150 ms):
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 }''
Para simplificar el uso de awk para analizar el resultado de objdump en relación con otras respuestas:
objdump -d filename | sed ''/<functionName>:/,/^$/!d''
Sugeriría usar gdb como el enfoque más simple. Incluso puede hacerlo como una línea, como:
gdb -batch -ex ''file /bin/ls'' -ex ''disassemble main''
disassemble/rs
para mostrar bytes fuente y raw también
Con este formato, se acerca mucho al objdump -S
output:
gdb -batch -ex "file $EXECUTABLE" -ex "disassemble/rs $FUNCTION"
C.A:
#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 desmontar
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.
awk soluciones
Imprima el párrafo como se menciona 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>/''
Cuando uso -S
, no creo que haya una manera a prueba de fallas, ya que los comentarios del 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 marcador que pueden aparecer 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 alternativa de 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 descarta la sección.
Nicolas Clifton le dio un WONTFIX https://sourceware.org/ml/binutils/2015-07/msg00004.html , probablemente porque la solución GDB cubre ese caso de uso.