作者descent (「雄辩是银,沉默是金」)
看板C_and_CPP
标题Re: [问题]fork疑问
时间Thu Jan 30 00:10:30 2020
我简化你的程式:
#include <unistd.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
char *ptr="abcdef";
pid_t pid;
pid = fork();
if (pid == 0)
{
printf("child ptr: %p\n", ptr);
}
else
{
printf("parent ptr: %p\n", ptr);
}
return 0;
}
执行结果:
parent ptr: 0x400624
child ptr: 0x400624
我在 Ubuntu 16.04.1 LTS 测试。
gcc 8.1
gcc -g -fno-pic f.c -o f
ptr 在 parent process 和 child process 都是一样的位址。
反组译
char *ptr="abcdef";
400551: 48 c7 45 f8 24 06 40 movq $0x400624,-0x8(%rbp)
ptr 位址是 0x400624, 看以下的反组译 0x400624, 0x61, 0x62 ~ 0x66,
就是 "abcdef"
400620: 01 00 add %eax,(%rax)
400622: 02 00 add (%rax),%al
400624: 61 (bad)
400625: 62 63 64 65 66 (bad) {%k5}
这整段 machine code 在 fork 之後还是长这个样子, 所以印出来的 ptr 这个值
自然会是一样的。
如果你想知道 fork 怎麽实作, 可以参考 Orange's 一个作业系统的实现, 里头有一章
在说明 fork 是怎麽实作的。
如果你不是在这环境测试, 可能无法得到这结果, 我不知道为什麽在
我的 debian, link 出来的位址和执行位址竟然不同。
※ 引述《b10007034 (Triven)》之铭言:
: https://i.imgur.com/MjKHbOu.png
: https://i.imgur.com/iUkvs5x.png
: 我照着图中程式在Ubuntu 18.04.3执行,有几个疑问想请教
: 为什麽child跟parent 的variable’s address一致呢?我以为copy on write会使得它们不
: 一样
: 承上题,一样的address不会造成它们aliasing吗?
: 谢谢看完!
--
纸上得来终觉浅,绝知此事要躬行。
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 180.217.252.148 (台湾)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1580314236.A.82A.html
1F:推 b0920075: 0x400624那部分的位置应该只是data section存放的data 01/30 01:54
2F:→ b0920075: ,不是 machine code...,除非你把process的数值都称作 01/30 01:54
3F:→ b0920075: machine code 01/30 01:54
应该是像你说的才是。
这部份一样都会在 fork 之後被复制。
4F:推 b0920075: 是说fork的实作应该在kernel内,linux发行版的同版本ke 01/30 01:59
5F:→ b0920075: rnel应该要一样吧,为啥会不一样? 01/30 01:59
6F:→ Lipraxde: data 当指令 dump...? 01/30 03:48
7F:→ Lipraxde: 位置不一样我还蛮好奇的,有图吗? 01/30 03:48
char *ptr="abcdef";
11ba: c7 45 f4 08 20 00 00 movl $0x2008,-0xc(%ebp)
0x2008 位址是 abcdef
2008: 61 popa
2009: 62 63 64 bound %esp,0x64(%ebx)
200c: 65 66 00 63 68
parent ptr: 0x5656a008
child ptr: 0x5656a008
ptr 应该要是 0x2008, 但结果却是 0x5656a008。
这是在 debian 上测试的结果。
我猜测是 loader 载入时加了一个 offset。
8F:→ b10007034: 谢大大回覆! 01/30 06:17
9F:推 b0920075: 这不就是PIE下的offset吗,要加上process的base addees 01/30 11:44
10F:→ b0920075: s才会是地址阿 01/30 11:44
我有试过 -fno-pie 也是这样。
在 debian 使用 -m32 才可以加上 -fno-pic -fno-pie。
否则会有以下错误。
gcc -g -fno-pic -fno-pie f.c -o f
/usr/bin/ld: /tmp/ccYo1k1x.o: relocation R_X86_64_32S against `.rodata' can
not be used when making a PIE object; recompile with -fPIE
看起来好像是 gcc 9 的关系, 我用 gcc5 编译之後, 可以取得和 ubuntu 相同结果。
不知道是不是这个的关系, --enable-default-pie
https://nanxiao.me/en/gccs-enable-enable-default-pie-option-make-you-stuck-at-relocation-r_x86_64_32s-against-error/
gcc -static -g -fno-pic -fno-pie f.c -o f
用这个也可以。
11F:→ Lipraxde: -fno-pic 没作用@@ 01/30 12:15
※ 编辑: descent (175.98.141.254 台湾), 01/30/2020 13:21:49
12F:推 b0920075: 喔喔所以是gcc的关系吗?如果是ubuntu用gcc9呢 01/30 16:44
13F:→ Lipraxde: 直接 -no-pie,不要 f 01/30 17:29
14F:→ descent: 感谢, 原来还有这个 option 01/30 17:59