0
.section .bss
        .lcomm stack, 4

.section .text

.globl _start
_start:
nop

movl %eip,$stack   --> How i can move ESP or any other registers value which will actually be ADDRESS , into STACK variable?

movl $4, %eax
movl $1, %ebx
movl $stack, %ecx
movl $4, %edx
int $0x80

movl $1, %eax
movl $0, %ebx
int $0x80

实际上,我想使用 WRITE 系统调用打印当前的 ESP 值,因为我将在我的 C 程序中将其用作内联汇编。

4

1 回答 1

1

此 GNU C/C++ 代码(GNU 因为它用于检索当前堆栈指针值的内联汇编风格)将打印堆栈指针的当前值(以十六进制表示)

static __inline__ void printESP(void) {
    static const hexdigit[] = "0123456789ABCDEF\n";
    uintptr_t SP;

    __asm__ __volatile__("mov %%esp, %0\n\t" : "=r"(SP));

    write(1, &hexdigit[SP >> 28], 1);
    write(1, &hexdigit[0xf & SP >> 24], 1);
    write(1, &hexdigit[0xf & SP >> 20], 1);
    write(1, &hexdigit[0xf & SP >> 16], 1);
    write(1, &hexdigit[0xf & SP >> 12], 1);
    write(1, &hexdigit[0xf & SP >> 8], 1);
    write(1, &hexdigit[0xf & SP >> 4], 1);
    write(1, &hexdigit[0xf & SP], 1);
    write(1, &hexdigit[16], 1);
}

由于static __inline__,gcc 在大多数情况下(实际上,如果您使用函数指针除外)实际上不会创建此函数,而是将代码直接嵌入到调用点。

您可以构建一个更复杂的部分,它会执行以下操作:

static __inline__ printESP(void)
{
    static const char hexdigit[] = "0123456789ABCDEF\n";
    uintptr_t SP;
    char buf[9];

    __asm__ __volatile__("mov %%esp, %0\n\t" : "=r"(SP));

    buf[0] = hexdigit[SP >> 28];
    buf[1] = hexdigit[0xf & SP >> 24];
    buf[2] = hexdigit[0xf & SP >> 20];
    buf[3] = hexdigit[0xf & SP >> 16];
    buf[4] = hexdigit[0xf & SP >> 12];
    buf[5] = hexdigit[0xf & SP >> 8];
    buf[6] = hexdigit[0xf & SP >> 4];
    buf[7] = hexdigit[0xf & SP];
    buf[8] = hexdigit[16];
    write(1, buf, 9);
}

这会在堆栈上构造一个临时缓冲区并write()仅调用一次。

第二段代码的缺点是它实际上消耗了 stackspace,这意味着如果你调用它,比如说,从一个溢出它的堆栈和/或损坏它的堆栈指针的函数中调用它,它就会崩溃。逐个字符发出地址的第一个微不足道可能仍然有效。

请注意您的初始汇编代码:这是使用全局缓冲区,因此不是线程安全的;如果你同时从多个线程调用它,它们会破坏变量并且你会得到垃圾。所以不,我不会帮助“修复”那个。

关于该方法的一般说明:就个人而言,我认为这就是调试器的用途。这种特定类型的运行时检测(以这种方式 - 通过直接打印值)相当无用;如果是运行时检测,那么最好记录到内存中的跟踪缓冲区,您可以在其中记录扩展信息,例如(部分)堆栈跟踪、线程 ID、时间戳、其他寄存器值等,以及堆栈指针。使用内存(环)缓冲区不依赖于文件描述符 1 的特殊含义,并且允许“上下文”信息比仅堆栈指针值更能描述正在发生的事情。

此外,如果该值不必 100% 准确,则可以使用gcc builtinsuintptr_t SP = (uintptr_t)__builtin_frame_address(0)代替。您根本不需要内联汇编。不同之处在于它会在函数入口处为您提供堆栈指针,而不是调用站点的当前堆栈指针,即它不考虑局部变量和其他“临时”的堆栈使用情况。

于 2012-12-10T13:48:23.863 回答