这里假设大家对于mmap都比较熟悉了,不熟悉的可以man 2 mmap来查看相关描述,熟悉了之后往下看,并且通过一个例子,来理解其中参数的含义。

  1. 首先我们编写一个简单的自增函数
package inc

func inc(n int) int {
	return n + 1
}

然后使用如下命令得到编译后代码

go tool compile -S -N inc.go

接着使用转储指令

go tool objdump -S inc.o

在终端可以得到如下:

TEXT "".inc(SB) gofile../home/ai/offer/inc/inc.go
func inc(n int) int {
  0x2ba                 48c744241000000000      MOVQ $0x0, 0x10(SP)     
        return n + 1
  0x2c3                 488b442408              MOVQ 0x8(SP), AX        
  0x2c8                 48ffc0                  INCQ AX                 
  0x2cb                 4889442410              MOVQ AX, 0x10(SP)       
  0x2d0                 c3                      RET       

然后我们将后续的地址放入一个字节切片当中:

code := []byte{
		0x48, 0xc7, 0x44, 0x24, 0x10, 0x00, 0x00, 0x00, 0x00,
		0x48, 0x8b, 0x44, 0x24, 0x08,
		0x48, 0xff, 0xc0,
		0x48, 0x89, 0x44, 0x24, 0x10,
		0xc3,
	}
// 其中字节切片中的内容就是上面的地址,用十六进制来表示


至此我们之前的工作已经做完了,然后开始我们的重头戏mmap系统调用,我们在虚拟内存当中分配一段空间,默认是以os.Getpagesize()大小为基本单位。

code := []byte{
		0x48, 0xc7, 0x44, 0x24, 0x10, 0x00, 0x00, 0x00, 0x00,
		0x48, 0x8b, 0x44, 0x24, 0x08,
		0x48, 0xff, 0xc0,
		0x48, 0x89, 0x44, 0x24, 0x10,
		0xc3,
	}
	

	// syscall mmap

	f, err := os.OpenFile("content.txt", os.O_RDWR|os.O_CREATE, 0777)
	f.Truncate(100)

	defer f.Close()
	if nil != err {
		log.Fatalln(err)
	}


	memory, err := syscall.Mmap(int(f.Fd()), 0, 100, syscall.PROT_READ|syscall.PROT_EXEC|syscall.PROT_WRITE, syscall.MAP_SHARED)
	defer syscall.Munmap(memory)

	copy(memory, code)
	//syscall.Sync()
	if nil != err {
		log.Fatalln(err)
	}


	memPtr := &memory

	inc := *(*func(int) int)(unsafe.Pointer(&memPtr))
	ret := inc(1)
	fmt.Println("ret is", ret)

todo: