Linker 是否有允许我移动堆栈起始地址的链接器脚本指令?

Linker 是否有允许我移动堆栈起始地址的链接器脚本指令?,linker,executable,elf,linker-scripts,executable-format,Linker,Executable,Elf,Linker Scripts,Executable Format,我正在尝试使用x86_64上的链接器脚本更改堆栈的开始位置。 我可以使用以下命令移动可执行文件的起始地址: PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x200000)); . = SEGMENT_START("text-segment", 0x200000) + SIZEOF_HEADERS; 我这样改变了我的全局: .data ALIGN(0x10000000) : { *(.data .d

我正在尝试使用x86_64上的链接器脚本更改堆栈的开始位置。 我可以使用以下命令移动可执行文件的起始地址:

PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x200000)); . = SEGMENT_START("text-segment", 0x200000) + SIZEOF_HEADERS;
我这样改变了我的全局:

 .data ALIGN(0x10000000)           :
{
*(.data .data.* .gnu.linkonce.d.*)
 SORT(CONSTRUCTORS)
}
我尝试使用以下方法移动堆栈区域:

. = 0x50000000;
.stack    :
{
 stack_start = .;

  PROVIDE( stack_start = . );
  *(.stack)
      . += 0x2000;
  stack_end = . ;
  PROVIDE( stack_end = . );
}
但这并没有让我有任何进展

下面是我用来测试堆栈位置的测试程序:

 #include <stdio.h>
 #include <stdlib.h>

int global_var = 555;

void test()
{
   int local_test = 666;

   printf("address of global_var: %p\n", &global_var);
   printf("address of local_test: %p\n", &local_test);

}

int main()
{
   int local_main = 5;
   printf("address of local_main: %p\n", &local_main);
   printf("address of test(): %p\n", &test);
   printf("address of main(): %p\n", &main);
   test();
   return 0;
}
虽然我甚至不确定stack_start和stack_end在x86_64上是否有效,因为我从arm online的链接器脚本教程中获得了这部分内容。我的链接器脚本没有错误或警告,所以我不确定发生了什么

如果您想知道为什么会有人这样做,这对安全性研究有影响

有没有一种方法可以使用链接器脚本实现我想要的功能?我简直不敢相信我可以移动.text、.bss和.data部分,但不能移动堆栈


更新:以下是对链接器不可行的原因的解释:

“您可能已经注意到,所有关于对象文件和 到目前为止,链接器只讨论了全局变量;没有 提到局部变量和动态分配的内存 前面提到过。这些数据不需要任何链接器 参与,因为他们的生命周期只有在项目完成时才会发生 在链接器完成其业务后长时间运行。“

是否有允许我移动堆栈起始地址的链接器脚本指令

在Linux上(您似乎正在使用):否

Linux上的堆栈位置由内核和当前值
ulimit-s
决定;它不会以任何方式编码到主可执行文件中

如果您想知道为什么会有人这样做,这对安全性研究有影响

如果您想显式地控制堆栈位置,您必须编写一个自定义的
ELF
加载程序,该加载程序将
mmap()
并按照内核的方式设置堆栈(以及glibc期望的设置方式),然后将控制权转移到
a.out
ld linux

Windows呢


我已经很久没有接触Windows了,但我相信那里的情况是类似的——内核决定堆栈位置。

谢谢你的回答。我自己的发现也朝着这个方向发展。很高兴有其他人确认我的理解。我只是好奇,既然你的答案集中在Linux上,你知道有没有办法在Windows上做到这一点?不过我关注的是Linux,所以你的答案100%适用。我的另一个后续问题是ulimit-s如何帮助改变堆栈位置,因为-s只是控制堆栈大小?@IvanAlagenchev我已经更新了答案。回复:
ulimit-s
——我记错了。事实上,这没有帮助。
address of local_main: 0x7fffffffe26c  <---- I want to move local vars
address of test(): 0x40050c
address of main(): 0x400547
address of global_var: 0x600a10
address of local_test: 0x7fffffffe24c <----  I want to move local vars
address of local_main: 0x7fffffffe26c   <--- unchanged
address of test(): 0x2005ac
address of main(): 0x2005e7
address of global_var: 0x10000010
address of local_test: 0x7fffffffe24c   <--- unchanged
 $ nm -n test.out
             w _ITM_deregisterTMCloneTable
             w _ITM_registerTMCloneTable
             w _Jv_RegisterClasses
             w __gmon_start__
             U __libc_start_main@@GLIBC_2.2.5
             U printf@@GLIBC_2.2.5
0000000000200460 T _init
00000000002004a0 T _start
00000000002004cc t call_gmon_start
00000000002004f0 t deregister_tm_clones
0000000000200520 t register_tm_clones
0000000000200560 t __do_global_dtors_aux
0000000000200580 t frame_dummy
00000000002005ac T test
00000000002005e7 T main
0000000000200650 T __libc_csu_fini
0000000000200660 T __libc_csu_init
00000000002006ec T _fini
00000000002006f8 R _IO_stdin_used
0000000000200870 r __FRAME_END__
0000000000400878 t __frame_dummy_init_array_entry
0000000000400878 t __init_array_start
0000000000400880 t __do_global_dtors_aux_fini_array_entry
0000000000400880 t __init_array_end
0000000000400888 d __JCR_END__
0000000000400888 d __JCR_LIST__
0000000000400890 d _DYNAMIC
0000000000400a78 d _GLOBAL_OFFSET_TABLE_
0000000010000000 D __data_start
0000000010000000 W data_start
0000000010000008 D __dso_handle
0000000010000010 D global_var
0000000010000018 D __TMC_END__
0000000020000000 A __bss_start
0000000020000000 A _edata
0000000020000000 b completed.6092
0000000050000000 B stack_start
0000000050002000 A _end
0000000050002000 B stack_end