Issue
This is my C program ... I was trying to print out ESP, EBP and EIP.
#include <stdio.h>
int main() {
register int i asm("esp");
printf("%#010x <= $ESP\n", i);
int a = 1;
int b = 2;
char c[] = "A";
char d[] = "B";
printf("%p d = %s \n", &d, d);
printf("%p c = %s \n", &c, c);
printf("%p b = %d \n", &b, b);
printf("%p a = %d \n", &a, a);
register int j asm("ebp");
printf("%#010x <= $EBP\n", j);
//register int k asm("eip");
//printf("%#010x <= $EIP\n", k);
return 0;
}
I don't have problem with ESP and EBP.
user@linux:~# ./memoryAddress
0xbffff650 <= $ESP
0xbffff654 d = B
0xbffff656 c = A
0xbffff658 b = 2
0xbffff65c a = 1
0xbffff668 <= $EBP
user@linux:~#
But when I try to put EIP code, I'm getting the following error when compiling it.
user@linux:~# gcc memoryAddress.c -o memoryAddress -g
memoryAddress.c: In function ‘main’:
memoryAddress.c:20:15: error: invalid register name for ‘k’
register int k asm("eip");
^
user@linux:~#
What's wrong with this code?
register int k asm("eip");
printf("%#010x <= $EIP\n", k);
Is it possible to print out EIP value via C programming?
If yes, please let me know how to do it.
Update
I've tested the code here ...
user@linux:~/c$ lscpu
Architecture: i686
CPU op-mode(s): 32-bit
Byte Order: Little Endian
Thanks @Antti Haapala and others for your help. The code works ... However, when I load it into GDB, the EIP value is different.
(gdb) b 31
Breakpoint 1 at 0x68f: file eip.c, line 31.
(gdb) i r $eip $esp $ebp
The program has no registers now.
(gdb) r
Starting program: /home/user/c/a.out
0x00000000 <= Low Memory Address
0x40055d <= main() function
0x4005a5 <= $EIP 72 bytes from main() function (start)
0xbffff600 <= $ESP (Top of the Stack)
0xbffff600 d = B
0xbffff602 c = A
0xbffff604 b = 2
0xbffff608 a = 1
0xbffff618 <= $EBP (Bottom of the Stack)
0xffffffff <= High Memory Address
Breakpoint 1, main () at eip.c:31
31 return 0;
(gdb) i r $eip $esp $ebp
eip 0x40068f 0x40068f <main+306>
esp 0xbffff600 0xbffff600
ebp 0xbffff618 0xbffff618
(gdb)
Here is the new code
#include <stdio.h>
#include <inttypes.h>
int main() {
register int i asm("esp");
printf("0x00000000 <= Low Memory Address\n");
printf("%p <= main() function\n", &main);
uint32_t eip;
asm volatile("1: lea 1b, %0;": "=a"(eip));
printf("0x%" PRIx32 " <= $EIP %" PRIu32 " bytes from main() function (start)\n",
eip, eip - (uint32_t)main);
int a = 1;
int b = 2;
char c[] = "A";
char d[] = "B";
printf("%#010x <= $ESP (Top of the Stack)\n", i);
printf("%p d = %s \n", &d, d);
printf("%p c = %s \n", &c, c);
printf("%p b = %d \n", &b, b);
printf("%p a = %d \n", &a, a);
register int j asm("ebp");
printf("%#010x <= $EBP (Bottom of the Stack)\n", j);
printf("0xffffffff <= High Memory Address\n");
return 0;
}
Solution
Please first read the QA Reading program counter directly - from there we can see that there are no mov
commands to access the EIP/RIP
directly, therefore you cannot use register asm
to get access to it. Instead at any point you can use those tricks. It is easiest in 64-bit mode, use
uint64_t rip;
asm volatile("1: lea 1b(%%rip), %0;": "=a"(rip));
to get the 64-bit instruction (thanks Michael Petch for pointing out that a label works with lea
here.
Demonstration:
#include <stdio.h>
#include <inttypes.h>
int main(void) {
uint64_t rip;
asm volatile("1: lea 1b(%%rip), %0;": "=a"(rip));
printf("%" PRIx64 "; %" PRIu64 " bytes from main start\n",
rip, rip - (uint64_t)main);
}
Then
% gcc -m64 rip.c -o rip; ./rip
55b7bf9e8659; 8 bytes from start of main
Proof that it is correct:
% gdb -batch -ex 'file ./rip' -ex 'disassemble main'
Dump of assembler code for function main:
0x000000000000064a <+0>: push %rbp
0x000000000000064b <+1>: mov %rsp,%rbp
0x000000000000064e <+4>: sub $0x10,%rsp
0x0000000000000652 <+8>: lea -0x7(%rip),%rax # 0x652 <main+8>
For 32-bit code it seems you can use lea
with a label - this didn't work for 64-bit code though.
#include <stdio.h>
#include <inttypes.h>
int main(void) {
uint32_t eip;
asm volatile("1: lea 1b, %0;": "=a"(eip));
printf("%" PRIx32 "; %" PRIu32 " bytes from main start\n",
eip, eip - (uint32_t)main);
}
Then
% gcc -m32 eip.c -o eip; ./eip
5663754a; 29 bytes from main start
Proof that it is correct:
% gdb -batch -ex 'file ./eip' -ex 'disassemble main'
Dump of assembler code for function main:
0x0000052d <+0>: lea 0x4(%esp),%ecx
0x00000531 <+4>: and $0xfffffff0,%esp
0x00000534 <+7>: pushl -0x4(%ecx)
0x00000537 <+10>: push %ebp
0x00000538 <+11>: mov %esp,%ebp
0x0000053a <+13>: push %ebx
0x0000053b <+14>: push %ecx
0x0000053c <+15>: sub $0x10,%esp
0x0000053f <+18>: call 0x529 <__x86.get_pc_thunk.dx>
0x00000544 <+23>: add $0x1a94,%edx
0x0000054a <+29>: lea 0x54a,%eax
(in the 32-bit version there are many more lea
commands, but this one is the "load my constant address here", which then will be corrected by the dynamic linker when it loads the exe).
Answered By - Antti Haapala -- Слава Україні Answer Checked By - Gilberto Lyons (WPSolving Admin)