From a5f75e760655728bf3e0b7ab5ea0a9a927db7e2e Mon Sep 17 00:00:00 2001 From: bonsthie Date: Mon, 1 Dec 2025 14:00:20 +0100 Subject: [PATCH] elf: add support for GNU indirect function symbol type (gnu_ifunc) This feature enables emission of IFUNC symbols for global directive. Example syntax: ```asm global func_ifunc:function global func:gnu_ifunc func equ func_ifunc ``` --- doc/outfmt.src | 9 +++++++++ output/elf.h | 1 + output/outelf.c | 2 ++ travis/test/gnu_ifunc.asm | 14 ++++++++++++++ travis/test/gnu_ifunc.json | 11 +++++++++++ travis/test/gnu_ifunc.o.t | Bin 0 -> 656 bytes 6 files changed, 37 insertions(+) create mode 100644 travis/test/gnu_ifunc.asm create mode 100644 travis/test/gnu_ifunc.json create mode 100644 travis/test/gnu_ifunc.o.t 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 0000000000000000000000000000000000000000..a810b581b7a480e49d76c070de859c0219fff1be GIT binary patch literal 656 zcmb<-^>JfjWMqH=Mg}_u1P><4z~F#jLfH-stPD&@qU13_c7ZS(n)U{$BRJ8-1GLos$UUJ4k`>66$G-d`QiXn;RL8k79b6>hXcx&fYOpsaVQr~1wak8fQvvF z==LA>=wARF5vspr>C_lvtKotY4B^T%w