How to call assembly in gdb?
Prior to GCC 5 (1), I don't know of a way to run arbitrary machine code unless you actually enter the machine code into memory and then run it.
If you want to run code that's already in memory, you can just set the instruction pointer to the start, a breakpoint at the end, then go. Then, after the breakpoint, change the instruction pointer back to its original value.
But I can't actually see the use case for this. That doesn't mean there isn't one, just that anything you can do by running code, you can also achieve by directly modifying the registers, flags, memory and so forth.
For example, the command:
info registers
will dump the current values of the registers while:
set $eax = 42
will change the eax
register to 42
.
You can also change memory in this way:
set *((char*)0xb7ffeca0) = 4
This writes a single byte to memory location 0xb7ffeca0
and you can also use that same method to store wider data types.
(1) GCC 5 allows you to compile and execute arbitrary code with the compile code
command, as documented here.
compile code
command
Introduced around 7.9, it allows code compilation and injection, documentation: https://sourceware.org/gdb/onlinedocs/gdb/Compiling-and-Injecting-Code.html
main.c
#include <stdio.h>
int main(void) {
int i = 0;
printf("%d\n", i);
return 0;
}
Compile and run:
gcc -ggdb3 -o main.out main.c
gdb main.out
Then in GDB:
(gdb) start
Temporary breakpoint 1 at 0x113d: file main.c, line 4.
Starting program: /home/ciro/test/main.out
Temporary breakpoint 1, main () at main.c:4
4 int i = 0;
(gdb) next
5 printf("%d\n", i);
(gdb) compile code int j = 1; i = j; asm("nop");
(gdb) continue
Continuing.
1
[Inferior 1 (process 30256) exited normally]
Program output:
1
For this to work in GDB 7.9.1, GCC 5.1 I had to run GDB with:
LD_LIBRARY_PATH="$(dirname "$(gcc -print-libgcc-file-name)"):$LD_LIBRARY_PATH" gdb main.out
so that libcc1.so
will be visible: that is a recent GCC component that exposes a C API to the cc1
compiler, but this was not needed anymore on Ubuntu 19.04. This was still required for C++ however on a minimal:
main.cpp
#include <iostream>
int main() {
int i = 0;
std::cout << i << std::endl;
}
and:
compile code int j = 1; i = j; asm("nop");
There are a few constructs that did not work as I expected:
return
: In the GDB compile code command, what language constructs behave exactly as if they were present in the original source?includes such as:
compile code printf('asdf\n')
in Ubuntu 19.04.
On main.c above,
printf
without include worked because we already included it in the source, but if I try it on an emptymain()
without the include it fails with:gdb command line:1:1: warning: incompatible implicit declaration of built-in function ‘printf’ gdb command line:1:1: note: include ‘<stdio.h>’ or provide a declaration of ‘printf’ gdb command line:1:8: warning: character constant too long for its type gdb command line:1:8: warning: passing argument 1 of ‘printf’ makes pointer from integer without a cast [-Wint-conversion] gdb command line:1:8: note: expected ‘const char *’ but argument is of type ‘int’ gdb command line:1:1: warning: format not a string literal and no format arguments [-Wformat-security]
In C++ Ubuntu 19.04:
compile code std::cout << "Hello world\n";
failed with:
*** WARNING *** there are active plugins, do not report this as a bug unless you can reproduce it without enabling any plugins. Event | Plugins PLUGIN_PRE_GENERICIZE | libcp1plugin PLUGIN_GGC_MARKING | libcp1plugin PLUGIN_PRAGMAS | libcp1plugin gdb command line:1:6: internal compiler error: in plugin_build_decl, at libcc1/libcp1plugin.cc:1059 Please submit a full bug report, with preprocessed source if appropriate. See <file:///usr/share/doc/gcc-8/README.Bugs> for instructions. Compilation failed.
See also: How to compile C++ code in GDB?