diff --git a/doc/outfmt.src b/doc/outfmt.src index c7f1cf57..b67382f3 100644 --- a/doc/outfmt.src +++ b/doc/outfmt.src @@ -1415,6 +1415,15 @@ Declaring the type and size of global symbols is necessary when writing shared library code. For more information, see \k{picglobal}. +NASM supports the GNU indirect function symbol type using the keyword +\c{gnu_ifunc}. This marks the symbol as \c{STT_GNU_IFUNC} and causes the +dynamic loader to call the symbol as a resolver at runtime. For example: + +\c global func_ifunc:function +\c +\c global func:gnu_ifunc +\c func equ func_ifunc + \S{elfextrn} \c{elf} Extensions to the \c{EXTERN} Directive\I{EXTERN, elf extensions to}\I{EXTERN, elf extensions to} diff --git a/output/elf.h b/output/elf.h index b4c6551a..6a779a83 100644 --- a/output/elf.h +++ b/output/elf.h @@ -232,6 +232,7 @@ #define STT_COMMON 5 /* Symbol is a common data object */ #define STT_TLS 6 /* Symbol is thread-local data object */ #define STT_NUM 7 /* Number of defined types */ +#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ /* Symbol visibilities */ #define STV_DEFAULT 0 /* Default symbol visibility rules */ diff --git a/output/outelf.c b/output/outelf.c index e03c1623..e3992415 100644 --- a/output/outelf.c +++ b/output/outelf.c @@ -886,6 +886,8 @@ static void elf_deflabel(char *name, int32_t segment, int64_t offset, case 9: if (!nasm_strnicmp(spcword, "protected", wlen)) sym->other = STV_PROTECTED; + else if (!nasm_strnicmp(spcword, "gnu_ifunc", wlen)) + type = STT_GNU_IFUNC; else ok = false; break; diff --git a/travis/test/gnu_ifunc.asm b/travis/test/gnu_ifunc.asm new file mode 100644 index 00000000..f8572cd8 --- /dev/null +++ b/travis/test/gnu_ifunc.asm @@ -0,0 +1,14 @@ +section .text + +global __foo_ifunc:function +global __foo_impl:function + +__foo_impl: + ret + +__foo_ifunc: + lea rax, [rel __foo_impl] + ret + +global foo:gnu_ifunc +foo equ __foo_ifunc diff --git a/travis/test/gnu_ifunc.json b/travis/test/gnu_ifunc.json new file mode 100644 index 00000000..0c347d43 --- /dev/null +++ b/travis/test/gnu_ifunc.json @@ -0,0 +1,11 @@ +[ + { + "description": "Test for GNU indirect function (STT_GNU_IFUNC) symbol emission", + "id": "gnu_ifunc", + "format": "elf64", + "source": "gnu_ifunc.asm", + "target": [ + { "output": "gnu_ifunc.o" } + ] + } +] diff --git a/travis/test/gnu_ifunc.o.t b/travis/test/gnu_ifunc.o.t new file mode 100644 index 00000000..a810b581 Binary files /dev/null and b/travis/test/gnu_ifunc.o.t differ