我是gcc编译基础知识的新手。据我所知,出于安全原因,堆栈是不可执行的。那我们怎样才能在堆栈上执行代码。我在一个函数返回指向函数的指针的情况下观察到了这一点。它不返回指向代码的指针,而是指向堆栈上具有要执行的代码的位置。如何在linux中允许这样做?
已经由gcc完成了。我想知道它怎么可能?
这是c代码:
#include<stdio.h>
typedef int (* funcptr) ();
funcptr f ()
{
int g ()
{
}
return (&g);
}
main ()
{
funcptr fp;
fp = f();
fp ();
}
以下是汇编代码在堆栈中生成代码的部分:
#Starting trampoline code. The trampoline code is a small
#piece of code set up inside the stack!!!. This code, when
#executed, loads ecx with the static link and calls the
#function g
movb $-71, (%eax) # This is B9, the opcode for
"movl address_in_next_loc ecx"
this, when executed, will
load the static link in ecx
movl %edx, 1(%eax) # address_in_next_loc=ebp-16
the static link effectively
movb $-23, 5(%eax) # This is E9. the opcode for
jmp addr_nxt_ins + offset_
in_nxt_loc
Since the offset_in_nxt_loc
is &g - addr_nxt_ins, this
results in a jump to &g
movl $g.1831, %ecx # Stores &g - addr_nxt_ins
leal 10(%eax), %edx #
subl %edx, %ecx #
movl %ecx, %edx #
movl %edx, 6(%eax) #
#End of trampoline code
答案 0 :(得分:1)
您将从堆中分配内存而不是堆栈。但是,由于现代处理器/操作系统允许区分包含代码的内存区域和包含数据的内存区域(出于明显的安全原因),这可能无法解决问题。
答案 1 :(得分:1)
您的C代码包含嵌套函数,因此GCC会将生成的目标文件的.note.GNU-stack
部分设置为x
(表示需要可执行堆栈)。
调用链接器时,它会检查此部分的所有提供的目标文件。由于其中一个输入文件的.note.GNU-stack
设置为x
,因此链接器知道堆栈必须是可执行文件。
为了表明这一点,最终可执行文件中的ELF标题GNU_STACK
添加了标记PF_X
。
命令:
readelf -l a.out | grep -A1 GNU_STACK
应该允许您看到RWE
标志而不是RW
。
内核在为进程设置内存映射时专门查找此标头。
中的更多详细信息答案 2 :(得分:0)