Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 不同Ubuntu版本的二进制执行差异_C++_Assembly_Ubuntu 14.04_Ubuntu 16.04_X86 64 - Fatal编程技术网

C++ 不同Ubuntu版本的二进制执行差异

C++ 不同Ubuntu版本的二进制执行差异,c++,assembly,ubuntu-14.04,ubuntu-16.04,x86-64,C++,Assembly,Ubuntu 14.04,Ubuntu 16.04,X86 64,我有密码: #include <iostream> void func3() { std::cout << "World!" << std::endl; } void func2() { std::cout << "Hello "; } void func1() { register long int a asm("rbp"); long int* ptr = (long int*)(a); *(ptr+1) = (lon

我有密码:

#include <iostream>

void func3()
{
  std::cout << "World!" << std::endl;
}

void func2()
{
  std::cout << "Hello ";
}

void func1()
{
  register long int a asm("rbp");
  long int* ptr = (long int*)(a);
  *(ptr+1) = (long int)&func2;
}

int main()
{
  func1();
  func3();

  return 0;
}
#包括
void func3()
{
标准::cout
为什么会发生这种情况

因为编译器可以自由地产生无效代码,当源是“未定义行为”时,源不是定义良好的C++,编译器决定生成机器代码。 即使在我的评论之后,您也没有费心告诉我们为什么您认为它应该起作用,以及是哪个思维过程将您带到了这个来源(您试图通过更改

f1
的返回地址来解决什么问题)所以我不能解释更多,除了你试图运行无效的源,你得到崩溃,这是一个非常正常的行为,C++ C++的生态系统,经常发生的方式,即使当你实际上试图避免它,并编写有效的C++,因为这不是那么简单。 <>记住“代码”>登记器、堆栈指针、堆栈内存、堆栈对齐、和<代码> ReT <代码>指令不是C++语言的一部分,没有定义要求C++编译器使用代码栈来控制代码的流动,C++编译器也可以决定使用自修改跳转,如果是iTo需要,所以返回地址永远不会出现在堆栈上,你必须修补跳转。虽然这是不太可能的,你可以期望x86代码使用<代码>调用+ ReT <代码>对,但是任何关于C++源栈状态的假设都是毫无意义的,底层实现可以很容易地把你所不知道的东西堆栈起来。我没料到

如何让它在14.04运行

在debugger中启动它并检查自己如何修改原始代码(不修改堆栈内容)工作正常,必须在堆栈上修改什么才能使
f1
跳转到
f2
。可能是一些填充或无用的保留堆栈空间使得
f1
f2
之间的堆栈结构不兼容,因此通过对堆栈内容进行一些修补,您肯定可以实现您想要的(对于具有特定编译选项的特定源)

当然,这不是一个稳定的解决方案,也就是说,在向
f1
f2
main
添加一些代码后,它肯定会崩溃,每个变量中可能只有很少的局部变量会破坏您的篡改,更不用说打开优化器,这可能会完全删除空函数


您试图做的事情与“retpoline”有点类似,因此您可以查看关于它的讨论和linux内核源代码,以查看实际问题解决方案(在一定程度上降低了安全漏洞,但代价高昂),这是我所能说出的做类似事情的唯一合法原因,因为返回地址篡改将使现代x86 CPU中的内部返回地址缓冲区不同步,这使得下一条
ret
指令在性能方面非常昂贵

EDIT:在嗅探
ret
传入时,CPU将推测性地执行进入
main
的返回路径-从它的内部返回地址缓冲区,在实际执行
ret
时,它将发现地址不匹配,因此它将抛出整个推测路径并提取+执行他将代码路径改为
f2
,这需要几个CPU周期来重新加载具有意外代码路径的缓存和缓冲区,并且无法使用推测路径上已经完成的工作)

因此,如果您的动机是避免
f1
中的
ret
返回
main
main
中的
call f2
,保存一条
ret+call
指令对,以使代码更快,那么实际上,由于现代x86 CPU的内部复杂性,您正在使代码更慢不像原来的8086那样简单地按照指令操作

出于性能原因,请将源代码保持如下状态:

void f1(){/*…某些代码…*/}
void f2(){/*…某些代码…*/}
void main(){
f1();
f2();
}

void f2(){/*…某些代码…*/}
void f1(){
/*…一些代码*/
f2();
}
void main(){
f1();
}

一个优化的现代C++编译器,在这个小的情况下,很可能将<代码> F1 <代码>和<代码> f2>代码>转换成<代码>主<代码>,在特定情况下权衡这种内联的利弊(也避免在比利润带来更多损害的情况下过多的内联)。.

真正的问题是16.04是如何工作的。对于
gcc-O0
,您最终使用
rbp
中的值作为
main
的返回地址

您的程序正好在Arch Linux上为我工作,带有他们的glibc 2.26-11包,因为它调用
main
时,恰好将
\uu libc\u csu\u init
的地址留在
rbp
中。因此
\uu libc\u csu init
额外运行一次(消耗堆栈中的返回地址),然后返回libc.so.6中的
(调用
main
call rax
之后的指令)。从那里开始,执行继续进行,就像
main
正常返回一样,因此清理代码刷新stdio/iostream缓冲区,最终执行
write
系统调用,将
Hello
写入stdout

您可以使用
objdump
查看或者当然可以查看您自己的二进制文件,或者使用
gdb
单步执行它

所以,你的程序在任何地方都能运行,这纯粹是运气(因为main的调用者在寄存器中留下了东西)。你应该期待它会崩溃。

当然,这只适用于
gcc-O0
,它启用
-fno省略帧指针
,并且不内联函数
func1:
    do stuff
     ...
    jmp  func2
  ...
  call  func2
  ret
Breakpoint 2, main () at ret-frob.cpp:41
1: *(void **) $rsp @ 4 = {0x7ffff7157f4a <__libc_start_main+234>, 0x11c00, 0x7fffffffe6e8, 0x1ffffe6f8}
(gdb) p (void*)$rbp
$9 = (void *) 0x5555555549c0 <__libc_csu_init>
func1 () at ret-frob.cpp:27
1: *(void **) $rsp @ 4 = {0x55555555494c <main()+9>, 0x5555555549c0 <__libc_csu_init>, 0x7ffff7157f4a <__libc_start_main+234>, 0x11c00}
1: *(void **) $rsp @ 4 = {0x555555554909 <func2()>, 0x5555555549c0 <__libc_csu_init>, 0x7ffff7157f4a <__libc_start_main+234>, 0x11c00}
1: *(void **) $rsp @ 4 = {0x5555555549c0 <__libc_csu_init>, 0x7ffff7157f4a <__libc_start_main+234>, 0x11c00, 0x7fffffffe6e8}
1: *(void **) $rsp @ 4 = {0x5555555549c0 <__libc_csu_init>, 0x7ffff7157f4a <__libc_start_main+234>, 0x11c00, 0x7fffffffe6e8}
1: *(void **) $rsp @ 4 = {0x7ffff7157f4a <__libc_start_main+234>, 0x11c00, 0x7fffffffe6e8, 0x1ffffe6f8}