diff options
Diffstat (limited to 'meta/recipes-devtools/patchelf')
10 files changed, 128 insertions, 349 deletions
diff --git a/meta/recipes-devtools/patchelf/patchelf/0001-Set-interpreter-only-when-necessary.patch b/meta/recipes-devtools/patchelf/patchelf/0001-Set-interpreter-only-when-necessary.patch new file mode 100644 index 0000000000..9a8216b3fe --- /dev/null +++ b/meta/recipes-devtools/patchelf/patchelf/0001-Set-interpreter-only-when-necessary.patch @@ -0,0 +1,31 @@ +From f5df94952e87eaa390e5c845bc48fdb3dbc31cc2 Mon Sep 17 00:00:00 2001 +From: Yuta Hayama <hayama@lineo.co.jp> +Date: Fri, 21 Jul 2023 10:47:02 +0900 +Subject: [PATCH] Set interpreter only when necessary + +If the given interpreter is already set, nothing needs to be done. +As with modifySoname(), it skips unnecessary processing. + +Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com> +--- +Upstream-Status: Submitted [https://github.com/NixOS/patchelf/pull/508] + + src/patchelf.cc | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/patchelf.cc b/src/patchelf.cc +index 86429c4..e562c49 100644 +--- a/src/patchelf.cc ++++ b/src/patchelf.cc +@@ -1460,6 +1460,11 @@ void ElfFile<ElfFileParamNames>::modifySoname(sonameMode op, const std::string & + template<ElfFileParams> + void ElfFile<ElfFileParamNames>::setInterpreter(const std::string & newInterpreter) + { ++ if (getInterpreter() == newInterpreter) { ++ debug("given interpreter is already set\n"); ++ return; ++ } ++ + std::string & section = replaceSection(".interp", newInterpreter.size() + 1); + setSubstr(section, 0, newInterpreter + '\0'); + changed = true; diff --git a/meta/recipes-devtools/patchelf/patchelf/0002-align-startOffset-with-p_align-instead-of-pagesize-f.patch b/meta/recipes-devtools/patchelf/patchelf/0002-align-startOffset-with-p_align-instead-of-pagesize-f.patch new file mode 100644 index 0000000000..7906f0f73b --- /dev/null +++ b/meta/recipes-devtools/patchelf/patchelf/0002-align-startOffset-with-p_align-instead-of-pagesize-f.patch @@ -0,0 +1,42 @@ +From 1198329b922f3cdddc3e87a7c81d7730b646c088 Mon Sep 17 00:00:00 2001 +From: Yuta Hayama <hayama@lineo.co.jp> +Date: Fri, 28 Jul 2023 16:22:31 +0900 +Subject: [PATCH] align startOffset with p_align instead of pagesize for + compatibility + +According to the ELF specification, the alignment of loadable process segments +should satisfy (p_vaddr mod pagesize) == (p_offset mod pagesize). However, +glibc earlier than 2.35 incorrectly requires that the LOAD segment be (p_vaddr +mod p_align) == (p_offset mod p_align), and will output the error message +"ELF load command address/offset not properly aligned" if this is not met. + +Since there are many systems that use glibc earlier than 2.35, it is preferable +that newly added LOAD segments satisfy (p_vaddr mod p_align) == (p_offset mod +p_align) for compatibility. + +Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com> +--- +Upstream-Status: Submitted [https://github.com/NixOS/patchelf/pull/510] + + src/patchelf.cc | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/src/patchelf.cc b/src/patchelf.cc +index 82b4b46..6edb81a 100644 +--- a/src/patchelf.cc ++++ b/src/patchelf.cc +@@ -843,7 +843,13 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary() + neededSpace += headerTableSpace; + debug("needed space is %d\n", neededSpace); + +- Elf_Off startOffset = roundUp(fileContents->size(), getPageSize()); ++ /* glibc earlier than 2.35 requires that the LOAD segment satisfies ++ (p_vaddr mod p_align) == (p_offset mod p_align). ++ The ELF specification requires that loadable process segments satisfy ++ (p_vaddr mod pagesize) == (p_offset mod pagesize), so glibc is probably ++ wrong, but here startOffset is calculated according to p_align for ++ compatibility. */ ++ Elf_Off startOffset = roundUp(fileContents->size(), alignStartPage); + + // In older version of binutils (2.30), readelf would check if the dynamic + // section segment is strictly smaller than the file (and not same size). diff --git a/meta/recipes-devtools/patchelf/patchelf/0003-make-LOAD-segment-extensions-based-on-p_align-instea.patch b/meta/recipes-devtools/patchelf/patchelf/0003-make-LOAD-segment-extensions-based-on-p_align-instea.patch new file mode 100644 index 0000000000..37eaf992d8 --- /dev/null +++ b/meta/recipes-devtools/patchelf/patchelf/0003-make-LOAD-segment-extensions-based-on-p_align-instea.patch @@ -0,0 +1,32 @@ +From 299ad5766921d593e11a42a8e4dec55b4b350876 Mon Sep 17 00:00:00 2001 +From: Yuta Hayama <hayama@lineo.co.jp> +Date: Mon, 31 Jul 2023 11:58:49 +0900 +Subject: [PATCH] make LOAD segment extensions based on p_align instead of + pagesize + +Since the p_align of the LOAD segment is no longer pagesize, the actual p_align +value is used to calculate for the LOAD segment extension. + +If calculated with pagesize, new LOAD segment may be added even though the +existing LOAD segment can be extended. + +Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com> +--- +Upstream-Status: Submitted [https://github.com/NixOS/patchelf/pull/510] + + src/patchelf.cc | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/patchelf.cc b/src/patchelf.cc +index 6edb81a..86429c4 100644 +--- a/src/patchelf.cc ++++ b/src/patchelf.cc +@@ -885,7 +885,7 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary() + rdi(lastSeg.p_type) == PT_LOAD && + rdi(lastSeg.p_flags) == (PF_R | PF_W) && + rdi(lastSeg.p_align) == alignStartPage) { +- auto segEnd = roundUp(rdi(lastSeg.p_offset) + rdi(lastSeg.p_memsz), getPageSize()); ++ auto segEnd = roundUp(rdi(lastSeg.p_offset) + rdi(lastSeg.p_memsz), alignStartPage); + if (segEnd == startOffset) { + auto newSz = startOffset + neededSpace - rdi(lastSeg.p_offset); + wri(lastSeg.p_filesz, wri(lastSeg.p_memsz, newSz)); diff --git a/meta/recipes-devtools/patchelf/patchelf/Increase-maxSize-to-64MB.patch b/meta/recipes-devtools/patchelf/patchelf/Increase-maxSize-to-64MB.patch deleted file mode 100644 index 49050a18d2..0000000000 --- a/meta/recipes-devtools/patchelf/patchelf/Increase-maxSize-to-64MB.patch +++ /dev/null @@ -1,46 +0,0 @@ -From e3658740ec100e4c8cf83295460b032979e1a99a Mon Sep 17 00:00:00 2001 -From: Fabio Berton <fabio.berton@ossystems.com.br> -Date: Fri, 9 Sep 2016 18:21:32 -0300 -Subject: [PATCH] Increase maxSize to 64MB -Organization: O.S. Systems Software LTDA. - -Fix error: - -/ -|ERROR: qemu-native-2.5.0-r1 do_populate_sysroot_setscene: '('patchelf-uninative', -|'--set-interpreter', '../build/tmp/sysroots-uninative/x86_64-linux/lib/ -|ld-linux-x86-64.so.2', '../build/tmp/work/x86_64-linux/qemu-native/2.5.0-r1/ -|sstate-install-populate_sysroot/x86_64-linux/usr/bin/qemu-mips64')' -|failed with exit code 1 and the following output: -|warning: working around a Linux kernel bug by creating a hole of 36032512 -|bytes in ā../build/tmp/work/x86_64-linux/qemu-native/2.5.0-r1/ -|sstate-install-populate_sysroot/x86_64-linux/usr/bin/qemu-mips64ā -|maximum file size exceeded -\ - -Similar issue is discussed here: -https://github.com/NixOS/patchelf/issues/47 - -Upstream-Status: Inappropriate [embedded specific] - -Signed-off-by: Fabio Berton <fabio.berton@ossystems.com.br> ---- - src/patchelf.cc | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/patchelf.cc b/src/patchelf.cc -index a59c12d..0fd7355 100644 ---- a/src/patchelf.cc -+++ b/src/patchelf.cc -@@ -279,7 +279,7 @@ static void readFile(string fileName) - struct stat st; - if (stat(fileName.c_str(), &st) != 0) error("stat"); - fileSize = st.st_size; -- maxSize = fileSize + 32 * 1024 * 1024; -+ maxSize = fileSize + 64 * 1024 * 1024; - - contents = (unsigned char *) malloc(fileSize + maxSize); - if (!contents) abort(); --- -2.1.4 - diff --git a/meta/recipes-devtools/patchelf/patchelf/Skip-empty-section-fixes-66.patch b/meta/recipes-devtools/patchelf/patchelf/Skip-empty-section-fixes-66.patch deleted file mode 100644 index 9ee8a554a7..0000000000 --- a/meta/recipes-devtools/patchelf/patchelf/Skip-empty-section-fixes-66.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 73526cb546ae6b00ea6169e40b01fb7b5f0dbb50 Mon Sep 17 00:00:00 2001 -From: Fabio Berton <fabio.berton@ossystems.com.br> -Date: Thu, 28 Jul 2016 11:05:06 -0300 -Subject: [PATCH] Skip empty section (fixes #66) -Organization: O.S. Systems Software LTDA. - -Upstream-Status: Pending - -Signed-off-by: Fabio Berton <fabio.berton@ossystems.com.br> ---- - src/patchelf.cc | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/src/patchelf.cc b/src/patchelf.cc -index 136098f..2677a26 100644 ---- a/src/patchelf.cc -+++ b/src/patchelf.cc -@@ -684,6 +684,9 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsExecutable() - for (unsigned int i = 1; i <= lastReplaced; ++i) { - Elf_Shdr & shdr(shdrs[i]); - string sectionName = getSectionName(shdr); -+ if (sectionName == "") { -+ continue; -+ } - debug("looking at section `%s'\n", sectionName.c_str()); - /* !!! Why do we stop after a .dynstr section? I can't - remember! */ --- -2.1.4 - diff --git a/meta/recipes-devtools/patchelf/patchelf/avoidholes.patch b/meta/recipes-devtools/patchelf/patchelf/avoidholes.patch deleted file mode 100644 index 0b45c39bda..0000000000 --- a/meta/recipes-devtools/patchelf/patchelf/avoidholes.patch +++ /dev/null @@ -1,163 +0,0 @@ -Different types of binaries create challenges for patchelf. In order to extend -sections they need to be moved within the binary. The current approach to -handling ET_DYN binaries is to move the INTERP section to the end of the file. -This means changing PT_PHDR to add an extra PT_LOAD section so that the new section -is mmaped into memory by the elf loader in the kernel. In order to extend PHDR, -this means moving it to the end of the file. - -Its documented in patchelf there is a kernel 'bug' which means that if you have holes -in memory between the base load address and the PT_LOAD segment that contains PHDR, -it will pass an incorrect PHDR address to ld.so and fail to load the binary, segfaulting. - -To avoid this, the code currently inserts space into the binary to ensure that when -loaded into memory there are no holes between the PT_LOAD sections. This inflates the -binaries by many MBs in some cases. Whilst we could make them sparse, there is a second -issue which is that strip can fail to process these binaries: - -$ strip fixincl -Not enough room for program headers, try linking with -N -[.note.ABI-tag]: Bad value - -This turns out to be due to libbfd not liking the relocated PHDR section either -(https://github.com/NixOS/patchelf/issues/10). - -Instead this patch implements a different approach, leaving PHDR where it is but extending -it in place to allow addition of a new PT_LOAD section. This overwrites sections in the -binary but those get moved to the end of the file in the new PT_LOAD section. - -This is based on patches linked from the above github issue, however whilst the idea -was good, the implementation wasn't correct and they've been rewritten here. - -RP -2017/3/7 - -Upstream-Status: Accepted - -Index: patchelf-0.9/src/patchelf.cc -=================================================================== ---- patchelf-0.9.orig/src/patchelf.cc -+++ patchelf-0.9/src/patchelf.cc -@@ -146,6 +146,8 @@ private: - string & replaceSection(const SectionName & sectionName, - unsigned int size); - -+ bool haveReplacedSection(const SectionName & sectionName); -+ - void writeReplacedSections(Elf_Off & curOff, - Elf_Addr startAddr, Elf_Off startOffset); - -@@ -497,6 +499,16 @@ unsigned int ElfFile<ElfFileParamNames>: - return 0; - } - -+template<ElfFileParams> -+bool ElfFile<ElfFileParamNames>::haveReplacedSection(const SectionName & sectionName) -+{ -+ ReplacedSections::iterator i = replacedSections.find(sectionName); -+ -+ if (i != replacedSections.end()) -+ return true; -+ return false; -+} -+ - - template<ElfFileParams> - string & ElfFile<ElfFileParamNames>::replaceSection(const SectionName & sectionName, -@@ -595,52 +607,52 @@ void ElfFile<ElfFileParamNames>::rewrite - - debug("last page is 0x%llx\n", (unsigned long long) startPage); - -+ /* Because we're adding a new section header, we're necessarily increasing -+ the size of the program header table. This can cause the first section -+ to overlap the program header table in memory; we need to shift the first -+ few segments to someplace else. */ -+ /* Some sections may already be replaced so account for that */ -+ unsigned int i = 1; -+ Elf_Addr pht_size = sizeof(Elf_Ehdr) + (phdrs.size() + 1)*sizeof(Elf_Phdr); -+ while( shdrs[i].sh_addr <= pht_size && i < rdi(hdr->e_shnum) ) { -+ if (not haveReplacedSection(getSectionName(shdrs[i]))) -+ replaceSection(getSectionName(shdrs[i]), shdrs[i].sh_size); -+ i++; -+ } - -- /* Compute the total space needed for the replaced sections and -- the program headers. */ -- off_t neededSpace = (phdrs.size() + 1) * sizeof(Elf_Phdr); -+ /* Compute the total space needed for the replaced sections */ -+ off_t neededSpace = 0; - for (ReplacedSections::iterator i = replacedSections.begin(); - i != replacedSections.end(); ++i) - neededSpace += roundUp(i->second.size(), sectionAlignment); - debug("needed space is %d\n", neededSpace); - -- - size_t startOffset = roundUp(fileSize, getPageSize()); - - growFile(startOffset + neededSpace); - -- - /* Even though this file is of type ET_DYN, it could actually be - an executable. For instance, Gold produces executables marked -- ET_DYN. In that case we can still hit the kernel bug that -- necessitated rewriteSectionsExecutable(). However, such -- executables also tend to start at virtual address 0, so -+ ET_DYN as does LD when linking with pie. If we move PT_PHDR, it -+ has to stay in the first PT_LOAD segment or any subsequent ones -+ if they're continuous in memory due to linux kernel constraints -+ (see BUGS). Since the end of the file would be after bss, we can't -+ move PHDR there, we therefore choose to leave PT_PHDR where it is but -+ move enough following sections such that we can add the extra PT_LOAD -+ section to it. This PT_LOAD segment ensures the sections at the end of -+ the file are mapped into memory for ld.so to process. -+ We can't use the approach in rewriteSectionsExecutable() -+ since DYN executables tend to start at virtual address 0, so - rewriteSectionsExecutable() won't work because it doesn't have -- any virtual address space to grow downwards into. As a -- workaround, make sure that the virtual address of our new -- PT_LOAD segment relative to the first PT_LOAD segment is equal -- to its offset; otherwise we hit the kernel bug. This may -- require creating a hole in the executable. The bigger the size -- of the uninitialised data segment, the bigger the hole. */ -+ any virtual address space to grow downwards into. */ - if (isExecutable) { - if (startOffset >= startPage) { - debug("shifting new PT_LOAD segment by %d bytes to work around a Linux kernel bug\n", startOffset - startPage); -- } else { -- size_t hole = startPage - startOffset; -- /* Print a warning, because the hole could be very big. */ -- fprintf(stderr, "warning: working around a Linux kernel bug by creating a hole of %zu bytes in ā%sā\n", hole, fileName.c_str()); -- assert(hole % getPageSize() == 0); -- /* !!! We could create an actual hole in the file here, -- but it's probably not worth the effort. */ -- growFile(fileSize + hole); -- startOffset += hole; - } - startPage = startOffset; - } - -- -- /* Add a segment that maps the replaced sections and program -- headers into memory. */ -+ /* Add a segment that maps the replaced sections into memory. */ - phdrs.resize(rdi(hdr->e_phnum) + 1); - wri(hdr->e_phnum, rdi(hdr->e_phnum) + 1); - Elf_Phdr & phdr = phdrs[rdi(hdr->e_phnum) - 1]; -@@ -653,15 +665,12 @@ void ElfFile<ElfFileParamNames>::rewrite - - - /* Write out the replaced sections. */ -- Elf_Off curOff = startOffset + phdrs.size() * sizeof(Elf_Phdr); -+ Elf_Off curOff = startOffset; - writeReplacedSections(curOff, startPage, startOffset); - assert(curOff == startOffset + neededSpace); - -- -- /* Move the program header to the start of the new area. */ -- wri(hdr->e_phoff, startOffset); -- -- rewriteHeaders(startPage); -+ /* Write out the updated program and section headers */ -+ rewriteHeaders(hdr->e_phoff); - } - - diff --git a/meta/recipes-devtools/patchelf/patchelf/fix-adjusting-startPage.patch b/meta/recipes-devtools/patchelf/patchelf/fix-adjusting-startPage.patch deleted file mode 100644 index f64cbed5cb..0000000000 --- a/meta/recipes-devtools/patchelf/patchelf/fix-adjusting-startPage.patch +++ /dev/null @@ -1,38 +0,0 @@ -commit 1cc234fea5600190d872329aca60e2365cefc39e -Author: Ed Bartosh <ed.bartosh@linux.intel.com> -Date: Fri Jul 21 12:33:53 2017 +0300 - -fix adjusting startPage - -startPage is adjusted unconditionally for all executables. -This results in incorrect addresses assigned to INTERP and LOAD -program headers, which breaks patched executable. - -Adjusting startPage variable only when startOffset > startPage -should fix this. - -This change is related to the issue NixOS#10 - -Signed-off-by: Ed Bartosh <ed.bartosh@linux.intel.com> - -Github PR: https://github.com/NixOS/patchelf/pull/127 - -Upstream-Status: Submitted - -diff --git a/src/patchelf.cc b/src/patchelf.cc -index cbd36c0..e9d7ea5 100644 ---- a/src/patchelf.cc -+++ b/src/patchelf.cc -@@ -720,10 +720,8 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary() - since DYN executables tend to start at virtual address 0, so - rewriteSectionsExecutable() won't work because it doesn't have - any virtual address space to grow downwards into. */ -- if (isExecutable) { -- if (startOffset >= startPage) { -- debug("shifting new PT_LOAD segment by %d bytes to work around a Linux kernel bug\n", startOffset - startPage); -- } -+ if (isExecutable && startOffset > startPage) { -+ debug("shifting new PT_LOAD segment by %d bytes to work around a Linux kernel bug\n", startOffset - startPage); - startPage = startOffset; - } - diff --git a/meta/recipes-devtools/patchelf/patchelf/handle-read-only-files.patch b/meta/recipes-devtools/patchelf/patchelf/handle-read-only-files.patch deleted file mode 100644 index 9fafec4b59..0000000000 --- a/meta/recipes-devtools/patchelf/patchelf/handle-read-only-files.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 2a603acb65993698c21f1c6eb7664f93ad830d52 Mon Sep 17 00:00:00 2001 -From: Fabio Berton <fabio.berton@ossystems.com.br> -Date: Fri, 9 Sep 2016 16:00:42 -0300 -Subject: [PATCH] handle read-only files -Organization: O.S. Systems Software LTDA. - -Patch from: -https://github.com/darealshinji/patchelf/commit/40e66392bc4b96e9b4eda496827d26348a503509 - -Upstream-Status: Pending - -Signed-off-by: Fabio Berton <fabio.berton@ossystems.com.br> ---- - src/patchelf.cc | 16 +++++++++++++++- - 1 file changed, 15 insertions(+), 1 deletion(-) - -diff --git a/src/patchelf.cc b/src/patchelf.cc -index 136098f..aea360e 100644 ---- a/src/patchelf.cc -+++ b/src/patchelf.cc -@@ -388,7 +388,17 @@ void ElfFile<ElfFileParamNames>::sortShdrs() - - static void writeFile(string fileName) - { -- int fd = open(fileName.c_str(), O_TRUNC | O_WRONLY); -+ struct stat st; -+ int fd; -+ -+ if (stat(fileName.c_str(), &st) != 0) -+ error("stat"); -+ -+ if (chmod(fileName.c_str(), 0600) != 0) -+ error("chmod"); -+ -+ fd = open(fileName.c_str(), O_TRUNC | O_WRONLY); -+ - if (fd == -1) - error("open"); - -@@ -397,6 +407,10 @@ static void writeFile(string fileName) - - if (close(fd) != 0) - error("close"); -+ -+ if (chmod(fileName.c_str(), st.st_mode) != 0) -+ error("chmod"); -+ - } - - --- -2.1.4 - diff --git a/meta/recipes-devtools/patchelf/patchelf_0.18.0.bb b/meta/recipes-devtools/patchelf/patchelf_0.18.0.bb new file mode 100644 index 0000000000..dece34240c --- /dev/null +++ b/meta/recipes-devtools/patchelf/patchelf_0.18.0.bb @@ -0,0 +1,23 @@ +SUMMARY = "Tool to allow editing of RPATH and interpreter fields in ELF binaries" +DESCRIPTION = "PatchELF is a simple utility for modifying existing ELF executables and libraries." +HOMEPAGE = "https://github.com/NixOS/patchelf" + +LICENSE = "GPL-3.0-only" + +SRC_URI = "git://github.com/NixOS/patchelf;protocol=https;branch=master \ + file://0001-Set-interpreter-only-when-necessary.patch \ + file://0002-align-startOffset-with-p_align-instead-of-pagesize-f.patch \ + file://0003-make-LOAD-segment-extensions-based-on-p_align-instea.patch \ +" +SRCREV = "99c24238981b7b1084313aca8f5c493bb46f302c" + +S = "${WORKDIR}/git" + +LIC_FILES_CHKSUM = "file://COPYING;md5=d32239bcb673463ab874e80d47fae504" + +inherit autotools + +PACKAGES += "${PN}-zsh-completion" +FILES:${PN}-zsh-completion = "${datadir}/zsh" + +BBCLASSEXTEND = "native nativesdk" diff --git a/meta/recipes-devtools/patchelf/patchelf_0.9.bb b/meta/recipes-devtools/patchelf/patchelf_0.9.bb deleted file mode 100644 index d70303963c..0000000000 --- a/meta/recipes-devtools/patchelf/patchelf_0.9.bb +++ /dev/null @@ -1,19 +0,0 @@ -SRC_URI = "http://nixos.org/releases/${BPN}/${BPN}-${PV}/${BPN}-${PV}.tar.bz2 \ - file://Skip-empty-section-fixes-66.patch \ - file://handle-read-only-files.patch \ - file://Increase-maxSize-to-64MB.patch \ - file://avoidholes.patch \ - file://fix-adjusting-startPage.patch \ -" - -LICENSE = "GPLv3" -SUMMARY = "Tool to allow editing of RPATH and interpreter fields in ELF binaries" - -SRC_URI[md5sum] = "d02687629c7e1698a486a93a0d607947" -SRC_URI[sha256sum] = "a0f65c1ba148890e9f2f7823f4bedf7ecad5417772f64f994004f59a39014f83" - -LIC_FILES_CHKSUM = "file://COPYING;md5=d32239bcb673463ab874e80d47fae504" - -inherit autotools - -BBCLASSEXTEND = "native nativesdk" |