🧤

Go言語でもPIE(Position Independent Executable)

2023/08/07に公開

PIE(Position Independent Executable)をGo言語で試してみました。

自身のメモリマップをダンプする関数

memmaps.go
package main

import (
    "io"
    "os"
    "log"
)

func dumpMemMaps(out io.Writer) {
    mapsFile, err := os.Open("/proc/self/maps")
    if err != nil {
        log.Fatalf("Failed to open /proc/self/maps: %v", err)
    }
    defer mapsFile.Close()

    _, err = io.Copy(out, mapsFile)
    if err != nil {
        log.Fatalf("Failed to copy /proc/self/maps to stderr: %v", err)
    }
}

func main() {
    dumpMemMaps(os.Stdout)
}

/proc/self/maps をダンプすることでそのプロセスのメモリマップを知ることができます。

今回使用したgoのversion.

$ go version
go version go1.20.7 linux/arm64

デフォルトのビルド

$ go build memmaps.go 
$ file memmaps
memmaps: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, Go BuildID=PNQ-fmnZlFWjpBRZVvRE/7AFfQUJxSeG8GmK7KlhU/kXH_ptDJBw085NNvtxgA/1D2iwvjOs7glWNmk3Xh1, with debug_info, not stripped

デフォルトのビルドではPIEではないstatic linkの実行ファイルができます。

$ ./memmaps 
00010000-00099000 r-xp 00000000 08:01 112368                             /home/koba/work/go/memmaps/memmaps
000a0000-00139000 r--p 00090000 08:01 112368                             /home/koba/work/go/memmaps/memmaps
00140000-00159000 rw-p 00130000 08:01 112368                             /home/koba/work/go/memmaps/memmaps
00159000-00190000 rw-p 00000000 00:00 0 
4000000000-4000400000 rw-p 00000000 00:00 0 
4000400000-4004000000 ---p 00000000 00:00 0 
ffff7d012000-ffff7f2ca000 rw-p 00000000 00:00 0 
ffff7f2ca000-ffff7fb47000 ---p 00000000 00:00 0 
ffff7fb47000-ffff7fb48000 rw-p 00000000 00:00 0 
ffff7fb48000-ffff9fad7000 ---p 00000000 00:00 0 
ffff9fad7000-ffff9fad8000 rw-p 00000000 00:00 0 
ffff9fad8000-ffffa3ac9000 ---p 00000000 00:00 0 
ffffa3ac9000-ffffa3aca000 rw-p 00000000 00:00 0 
ffffa3aca000-ffffa42c7000 ---p 00000000 00:00 0 
ffffa42c7000-ffffa42c8000 rw-p 00000000 00:00 0 
ffffa42c8000-ffffa43c7000 ---p 00000000 00:00 0 
ffffa43c7000-ffffa4427000 rw-p 00000000 00:00 0 
ffffa4427000-ffffa4429000 r--p 00000000 00:00 0                          [vvar]
ffffa4429000-ffffa442a000 r-xp 00000000 00:00 0                          [vdso]
ffffe9cba000-ffffe9cdb000 rw-p 00000000 00:00 0                          [stack]
$ ./memmaps 
00010000-00099000 r-xp 00000000 08:01 112368                             /home/koba/work/go/memmaps/memmaps
000a0000-00139000 r--p 00090000 08:01 112368                             /home/koba/work/go/memmaps/memmaps
00140000-00159000 rw-p 00130000 08:01 112368                             /home/koba/work/go/memmaps/memmaps
00159000-00190000 rw-p 00000000 00:00 0 
4000000000-4000400000 rw-p 00000000 00:00 0 
4000400000-4004000000 ---p 00000000 00:00 0 
ffff64b6b000-ffff66de3000 rw-p 00000000 00:00 0 
ffff66de3000-ffff67660000 ---p 00000000 00:00 0 
ffff67660000-ffff67661000 rw-p 00000000 00:00 0 
ffff67661000-ffff875f0000 ---p 00000000 00:00 0 
ffff875f0000-ffff875f1000 rw-p 00000000 00:00 0 
ffff875f1000-ffff8b5e2000 ---p 00000000 00:00 0 
ffff8b5e2000-ffff8b5e3000 rw-p 00000000 00:00 0 
ffff8b5e3000-ffff8bde0000 ---p 00000000 00:00 0 
ffff8bde0000-ffff8bde1000 rw-p 00000000 00:00 0 
ffff8bde1000-ffff8bee0000 ---p 00000000 00:00 0 
ffff8bee0000-ffff8bf40000 rw-p 00000000 00:00 0 
ffff8bf40000-ffff8bf42000 r--p 00000000 00:00 0                          [vvar]
ffff8bf42000-ffff8bf43000 r-xp 00000000 00:00 0                          [vdso]
ffffe2c8f000-ffffe2cb0000 rw-p 00000000 00:00 0                          [stack]

スタックエリアは変わりますが、プログラムのロードされるアドレスは変わりません。

PIEのビルド

-buildmode=pie をつけてビルドするとPIEになります。

$ go build -buildmode=pie memmaps.go 
$ file ./memmaps
./memmaps: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, Go BuildID=f_K_bSR-AYjJSOncC3LL/-4QJukj4SMkr04i0rzS8/1Pyf6Veo7S4-rTMpOK6A/prI3NQ8EctmsgCYNwX0x, with debug_info, not stripped

PIEですが、前の記事のようにstatic-pieではなくて、ダイナミックリンクになっていました。

実行してメモリマップを出してみます。

$ ./memmaps 
4000000000-4000400000 rw-p 00000000 00:00 0 
4000400000-4004000000 ---p 00000000 00:00 0 
aaaab1240000-aaaab12cc000 r-xp 00000000 08:01 112374                     /home/koba/work/go/memmaps/memmaps
aaaab12d0000-aaaab130f000 r--p 00090000 08:01 112374                     /home/koba/work/go/memmaps/memmaps
aaaab1310000-aaaab1388000 r--p 000d0000 08:01 112374                     /home/koba/work/go/memmaps/memmaps
aaaab1388000-aaaab1389000 rw-p 00148000 08:01 112374                     /home/koba/work/go/memmaps/memmaps
aaaab1390000-aaaab13a9000 rw-p 00150000 08:01 112374                     /home/koba/work/go/memmaps/memmaps
aaaab13a9000-aaaab13e0000 rw-p 00000000 00:00 0 
ffff95ac0000-ffff97d78000 rw-p 00000000 00:00 0 
ffff97d78000-ffff985f5000 ---p 00000000 00:00 0 
ffff985f5000-ffff985f6000 rw-p 00000000 00:00 0 
ffff985f6000-ffffb8585000 ---p 00000000 00:00 0 
ffffb8585000-ffffb8586000 rw-p 00000000 00:00 0 
ffffb8586000-ffffbc577000 ---p 00000000 00:00 0 
ffffbc577000-ffffbc578000 rw-p 00000000 00:00 0 
ffffbc578000-ffffbcd75000 ---p 00000000 00:00 0 
ffffbcd75000-ffffbcd76000 rw-p 00000000 00:00 0 
ffffbcd76000-ffffbce75000 ---p 00000000 00:00 0 
ffffbce75000-ffffbced5000 rw-p 00000000 00:00 0 
ffffbced5000-ffffbcf00000 r-xp 00000000 08:01 4871                       /usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1
ffffbcf0a000-ffffbcf0c000 rw-p 00000000 00:00 0 
ffffbcf0c000-ffffbcf0e000 r--p 00000000 00:00 0                          [vvar]
ffffbcf0e000-ffffbcf0f000 r-xp 00000000 00:00 0                          [vdso]
ffffbcf0f000-ffffbcf13000 rw-p 0002a000 08:01 4871                       /usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1
ffffe8fbb000-ffffe8fdc000 rw-p 00000000 00:00 0                          [stack]
$ ./memmaps 
4000000000-4000400000 rw-p 00000000 00:00 0 
4000400000-4004000000 ---p 00000000 00:00 0 
aaaaaf7c0000-aaaaaf84c000 r-xp 00000000 08:01 112374                     /home/koba/work/go/memmaps/memmaps
aaaaaf850000-aaaaaf88f000 r--p 00090000 08:01 112374                     /home/koba/work/go/memmaps/memmaps
aaaaaf890000-aaaaaf908000 r--p 000d0000 08:01 112374                     /home/koba/work/go/memmaps/memmaps
aaaaaf908000-aaaaaf909000 rw-p 00148000 08:01 112374                     /home/koba/work/go/memmaps/memmaps
aaaaaf910000-aaaaaf929000 rw-p 00150000 08:01 112374                     /home/koba/work/go/memmaps/memmaps
aaaaaf929000-aaaaaf960000 rw-p 00000000 00:00 0 
ffff75f1c000-ffff781d4000 rw-p 00000000 00:00 0 
ffff781d4000-ffff78a51000 ---p 00000000 00:00 0 
ffff78a51000-ffff78a52000 rw-p 00000000 00:00 0 
ffff78a52000-ffff989e1000 ---p 00000000 00:00 0 
ffff989e1000-ffff989e2000 rw-p 00000000 00:00 0 
ffff989e2000-ffff9c9d3000 ---p 00000000 00:00 0 
ffff9c9d3000-ffff9c9d4000 rw-p 00000000 00:00 0 
ffff9c9d4000-ffff9d1d1000 ---p 00000000 00:00 0 
ffff9d1d1000-ffff9d1d2000 rw-p 00000000 00:00 0 
ffff9d1d2000-ffff9d2d1000 ---p 00000000 00:00 0 
ffff9d2d1000-ffff9d331000 rw-p 00000000 00:00 0 
ffff9d331000-ffff9d35c000 r-xp 00000000 08:01 4871                       /usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1
ffff9d366000-ffff9d368000 rw-p 00000000 00:00 0 
ffff9d368000-ffff9d36a000 r--p 00000000 00:00 0                          [vvar]
ffff9d36a000-ffff9d36b000 r-xp 00000000 00:00 0                          [vdso]
ffff9d36b000-ffff9d36f000 rw-p 0002a000 08:01 4871                       /usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1
fffff85e2000-fffff8603000 rw-p 00000000 00:00 0                          [stack]

2回目の実行ではロードされるアドレスが変わっていることがわかります。

buildmodeで指定できるものは以下のように調べることができます。

$ go help buildmode
The 'go build' and 'go install' commands take a -buildmode argument which
indicates which kind of object file is to be built. Currently supported values
are:

	-buildmode=archive
		Build the listed non-main packages into .a files. Packages named
		main are ignored.

	-buildmode=c-archive
		Build the listed main package, plus all packages it imports,
		into a C archive file. The only callable symbols will be those
		functions exported using a cgo //export comment. Requires
		exactly one main package to be listed.

	-buildmode=c-shared
		Build the listed main package, plus all packages it imports,
		into a C shared library. The only callable symbols will
		be those functions exported using a cgo //export comment.
		Requires exactly one main package to be listed.

	-buildmode=default
		Listed main packages are built into executables and listed
		non-main packages are built into .a files (the default
		behavior).

	-buildmode=shared
		Combine all the listed non-main packages into a single shared
		library that will be used when building with the -linkshared
		option. Packages named main are ignored.

	-buildmode=exe
		Build the listed main packages and everything they import into
		executables. Packages not named main are ignored.

	-buildmode=pie
		Build the listed main packages and everything they import into
		position independent executables (PIE). Packages not named
		main are ignored.

	-buildmode=plugin
		Build the listed main packages, plus all packages that they
		import, into a Go plugin. Packages not named main are ignored.

On AIX, when linking a C program that uses a Go archive built with
-buildmode=c-archive, you must pass -Wl,-bnoobjreorder to the C compiler.

Go言語でもstatic-pie

外部リンカを使用するように指定することで、Go言語でもstatic-pieにすることができました。

$ go build -buildmode=pie -ldflags "-linkmode 'external' -extldflags '-static-pie'" memmaps.go
$ file memmaps
memmaps: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (GNU/Linux), static-pie linked, BuildID[sha1]=65449e89b1f748c30b250a59927ba060a8ed96d4, for GNU/Linux 3.7.0, with debug_info, not stripped
$ ./memmaps 
4000000000-4000400000 rw-p 00000000 00:00 0 
4000400000-4004000000 ---p 00000000 00:00 0 
aaaab0ca4000-aaaab0cc6000 rw-p 00000000 00:00 0                          [heap]
ffff5c000000-ffff5c021000 rw-p 00000000 00:00 0 
ffff5c021000-ffff60000000 ---p 00000000 00:00 0 
ffff64000000-ffff64021000 rw-p 00000000 00:00 0 
ffff64021000-ffff68000000 ---p 00000000 00:00 0 
ffff68000000-ffff68021000 rw-p 00000000 00:00 0 
ffff68021000-ffff6c000000 ---p 00000000 00:00 0 
ffff6c000000-ffff6c021000 rw-p 00000000 00:00 0 
ffff6c021000-ffff70000000 ---p 00000000 00:00 0 
ffff71fc0000-ffff71fd0000 ---p 00000000 00:00 0 
ffff71fd0000-ffff727d0000 rw-p 00000000 00:00 0 
ffff727d0000-ffff727e0000 ---p 00000000 00:00 0 
ffff727e0000-ffff72fe0000 rw-p 00000000 00:00 0 
ffff72fe0000-ffff72ff0000 ---p 00000000 00:00 0 
ffff72ff0000-ffff737f0000 rw-p 00000000 00:00 0 
ffff737f0000-ffff73800000 ---p 00000000 00:00 0 
ffff73800000-ffff74000000 rw-p 00000000 00:00 0 
ffff74000000-ffff74021000 rw-p 00000000 00:00 0 
ffff74021000-ffff78000000 ---p 00000000 00:00 0 
ffff7807e000-ffff780fe000 rw-p 00000000 00:00 0 
ffff780fe000-ffff7810e000 ---p 00000000 00:00 0 
ffff7810e000-ffff7ab46000 rw-p 00000000 00:00 0 
ffff7ab46000-ffff7b3c3000 ---p 00000000 00:00 0 
ffff7b3c3000-ffff7b3c4000 rw-p 00000000 00:00 0 
ffff7b3c4000-ffff9b353000 ---p 00000000 00:00 0 
ffff9b353000-ffff9b354000 rw-p 00000000 00:00 0 
ffff9b354000-ffff9f345000 ---p 00000000 00:00 0 
ffff9f345000-ffff9f346000 rw-p 00000000 00:00 0 
ffff9f346000-ffff9fb43000 ---p 00000000 00:00 0 
ffff9fb43000-ffff9fb44000 rw-p 00000000 00:00 0 
ffff9fb44000-ffff9fc43000 ---p 00000000 00:00 0 
ffff9fc43000-ffff9fca3000 rw-p 00000000 00:00 0 
ffff9fca3000-ffff9fe06000 r-xp 00000000 08:01 171902                     /home/koba/work/go/memmaps/memmaps
ffff9fe12000-ffff9fe14000 r--p 00000000 00:00 0                          [vvar]
ffff9fe14000-ffff9fe15000 r-xp 00000000 00:00 0                          [vdso]
ffff9fe15000-ffff9fe93000 r--p 00162000 08:01 171902                     /home/koba/work/go/memmaps/memmaps
ffff9fe93000-ffff9feae000 rw-p 001e0000 08:01 171902                     /home/koba/work/go/memmaps/memmaps
ffff9feae000-ffff9feeb000 rw-p 00000000 00:00 0 
ffffd6b5d000-ffffd6b7e000 rw-p 00000000 00:00 0                          [stack]
$ ./memmaps 
4000000000-4000400000 rw-p 00000000 00:00 0 
4000400000-4004000000 ---p 00000000 00:00 0 
aaaab4efd000-aaaab4f1f000 rw-p 00000000 00:00 0                          [heap]
ffff64000000-ffff64021000 rw-p 00000000 00:00 0 
ffff64021000-ffff68000000 ---p 00000000 00:00 0 
ffff6c000000-ffff6c021000 rw-p 00000000 00:00 0 
ffff6c021000-ffff70000000 ---p 00000000 00:00 0 
ffff70000000-ffff70021000 rw-p 00000000 00:00 0 
ffff70021000-ffff74000000 ---p 00000000 00:00 0 
ffff74000000-ffff74021000 rw-p 00000000 00:00 0 
ffff74021000-ffff78000000 ---p 00000000 00:00 0 
ffff79fc0000-ffff79fd0000 ---p 00000000 00:00 0 
ffff79fd0000-ffff7a7d0000 rw-p 00000000 00:00 0 
ffff7a7d0000-ffff7a7e0000 ---p 00000000 00:00 0 
ffff7a7e0000-ffff7afe0000 rw-p 00000000 00:00 0 
ffff7afe0000-ffff7aff0000 ---p 00000000 00:00 0 
ffff7aff0000-ffff7b7f0000 rw-p 00000000 00:00 0 
ffff7b7f0000-ffff7b800000 ---p 00000000 00:00 0 
ffff7b800000-ffff7c000000 rw-p 00000000 00:00 0 
ffff7c000000-ffff7c021000 rw-p 00000000 00:00 0 
ffff7c021000-ffff80000000 ---p 00000000 00:00 0 
ffff80119000-ffff80199000 rw-p 00000000 00:00 0 
ffff80199000-ffff801a9000 ---p 00000000 00:00 0 
ffff801a9000-ffff82be1000 rw-p 00000000 00:00 0 
ffff82be1000-ffff8345e000 ---p 00000000 00:00 0 
ffff8345e000-ffff8345f000 rw-p 00000000 00:00 0 
ffff8345f000-ffffa33ee000 ---p 00000000 00:00 0 
ffffa33ee000-ffffa33ef000 rw-p 00000000 00:00 0 
ffffa33ef000-ffffa73e0000 ---p 00000000 00:00 0 
ffffa73e0000-ffffa73e1000 rw-p 00000000 00:00 0 
ffffa73e1000-ffffa7bde000 ---p 00000000 00:00 0 
ffffa7bde000-ffffa7bdf000 rw-p 00000000 00:00 0 
ffffa7bdf000-ffffa7cde000 ---p 00000000 00:00 0 
ffffa7cde000-ffffa7d3e000 rw-p 00000000 00:00 0 
ffffa7d3e000-ffffa7ea1000 r-xp 00000000 08:01 171902                     /home/koba/work/go/memmaps/memmaps
ffffa7ead000-ffffa7eaf000 r--p 00000000 00:00 0                          [vvar]
ffffa7eaf000-ffffa7eb0000 r-xp 00000000 00:00 0                          [vdso]
ffffa7eb0000-ffffa7f2e000 r--p 00162000 08:01 171902                     /home/koba/work/go/memmaps/memmaps
ffffa7f2e000-ffffa7f49000 rw-p 001e0000 08:01 171902                     /home/koba/work/go/memmaps/memmaps
ffffa7f49000-ffffa7f86000 rw-p 00000000 00:00 0 
ffffed2a8000-ffffed2c9000 rw-p 00000000 00:00 0                          [stack]

関連

https://zenn.dev/tetsu_koba/articles/ecde4c6b5073bd
https://zenn.dev/tetsu_koba/articles/f08100a8fc4c34

Discussion