From 1d948c839d61682281b5ca702b53d3a2df853a34 Mon Sep 17 00:00:00 2001 From: "Markus F.X.J. Oberhumer" Date: Thu, 21 Dec 2000 18:31:00 +0000 Subject: [PATCH] Moved the generic linux/386 format into the new p_lx_exc.{h,cpp} files. committer: mfx 977423460 +0000 --- src/Makefile | 17 ++-- src/p_lx_elf.cpp | 1 + src/p_lx_exc.cpp | 237 +++++++++++++++++++++++++++++++++++++++++++++++ src/p_lx_exc.h | 69 ++++++++++++++ src/p_lx_sep.cpp | 1 + src/p_lx_sh.cpp | 1 + src/p_unix.cpp | 192 -------------------------------------- src/p_unix.h | 30 ------ src/packmast.cpp | 3 +- 9 files changed, 321 insertions(+), 230 deletions(-) create mode 100644 src/p_lx_exc.cpp create mode 100644 src/p_lx_exc.h diff --git a/src/Makefile b/src/Makefile index 134d2de2..ca2a4d54 100644 --- a/src/Makefile +++ b/src/Makefile @@ -61,7 +61,8 @@ OBJECTS1 = \ compress$o except$o file$o lefile$o \ filter$o mem$o msg$o stdcxx$o work$o ui$o \ packer$o packhead$o packmast$o \ - p_com$o p_djgpp2$o p_exe$o p_lx_elf$o p_lx_sep$o p_lx_sh$o \ + p_com$o p_djgpp2$o p_exe$o \ + p_lx_elf$o p_lx_exc$o p_lx_sep$o p_lx_sh$o \ p_sys$o p_tmt$o p_tos$o \ p_unix$o p_vmlinz$o p_w32pe$o p_wcle$o @@ -446,7 +447,8 @@ mygetopt$o: mygetopt.h packer$o: packer.h filter.h linker.h ui.h version.h packhead$o: packer.h packmast$o: packmast.h packer.h lefile.h \ - p_com.h p_djgpp2.h p_exe.h p_lx_elf.h p_lx_sep.h p_lx_sh.h \ + p_com.h p_djgpp2.h p_exe.h \ + p_lx_elf.h p_lx_exc.h p_lx_sep.h p_lx_sh.h \ p_sys.h p_tmt.h p_tos.h \ p_unix.h p_vmlinz.h p_vxd.h p_w32pe.h p_wcle.h ui$o: packer.h ui.h @@ -458,10 +460,12 @@ p_djgpp2$o: packer.h p_djgpp2.h stub/stubify.h \ stub/l_djgpp2.h p_exe$o: packer.h p_exe.h \ stub/l_exe.h -p_lx_elf$o: packer.h p_lx_elf.h p_unix.h p_elf.h \ +p_lx_elf$o: packer.h p_unix.h p_elf.h p_lx_exc.h p_lx_elf.h \ stub/l_le_n2b.h stub/l_le_n2d.h -p_lx_sep$o: packer.h p_lx_sep.h p_lx_elf.h p_unix.h p_elf.h -p_lx_sh$o: packer.h p_lx_sh.h p_unix.h p_elf.h \ +p_lx_exc$o: packer.h p_unix.h p_elf.h p_lx_exc.h \ + stub/l_lx_n2b.h stub/l_lx_n2d.h +p_lx_sep$o: packer.h p_unix.h p_elf.h p_lx_exc.h p_lx_elf.h p_lx_sep.h +p_lx_sh$o: packer.h p_unix.h p_elf.h p_lx_exc.h p_lx_sh.h \ stub/l_sh_n2b.h stub/l_sh_n2d.h p_sys$o: packer.h p_sys.h p_com.h \ stub/l_sys.h @@ -470,8 +474,7 @@ p_tmt$o: packer.h p_tmt.h \ p_tos$o: packer.h p_tos.h \ stub/l_t_n2b.h stub/l_t_n2bs.h \ stub/l_t_n2d.h stub/l_t_n2ds.h -p_unix$o: packer.h p_unix.h p_elf.h \ - stub/l_lx_n2b.h stub/l_lx_n2d.h +p_unix$o: packer.h p_unix.h p_elf.h p_vmlinz$o: packer.h p_vmlinz.h \ stub/l_vmlinz.h p_w32pe$o: packer.h p_w32pe.h \ diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp index d639e95d..892b51c5 100644 --- a/src/p_lx_elf.cpp +++ b/src/p_lx_elf.cpp @@ -36,6 +36,7 @@ #include "packer.h" #include "p_elf.h" #include "p_unix.h" +#include "p_lx_exc.h" #include "p_lx_elf.h" diff --git a/src/p_lx_exc.cpp b/src/p_lx_exc.cpp new file mode 100644 index 00000000..3214fc77 --- /dev/null +++ b/src/p_lx_exc.cpp @@ -0,0 +1,237 @@ +/* p_lx_exc.cpp -- + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996-2000 Laszlo Molnar + All Rights Reserved. + + UPX and the UCL library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer Laszlo Molnar + markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu + */ + + +#include "conf.h" + +#include "file.h" +#include "packer.h" +#include "p_elf.h" +#include "p_unix.h" +#include "p_lx_exc.h" + + +/************************************************************************* +// linux/386 (generic "execve" format) +**************************************************************************/ + +static const +#include "stub/l_lx_n2b.h" +static const +#include "stub/l_lx_n2d.h" + + +int PackLinuxI386::getCompressionMethod() const +{ + if (M_IS_NRV2B(opt->method)) + return M_NRV2B_LE32; + if (M_IS_NRV2D(opt->method)) + return M_NRV2D_LE32; + return opt->level > 1 && file_size >= 512*1024 ? M_NRV2D_LE32 : M_NRV2B_LE32; +} + + +const upx_byte *PackLinuxI386::getLoader() const +{ + if (M_IS_NRV2B(opt->method)) + return linux_i386exec_nrv2b_loader; + if (M_IS_NRV2D(opt->method)) + return linux_i386exec_nrv2d_loader; + return NULL; +} + + +int PackLinuxI386::getLoaderSize() const +{ + if (0!=lsize) { + return lsize; + } + if (M_IS_NRV2B(opt->method)) + return sizeof(linux_i386exec_nrv2b_loader); + if (M_IS_NRV2D(opt->method)) + return sizeof(linux_i386exec_nrv2d_loader); + return 0; +} + + +int PackLinuxI386::getLoaderPrefixSize() const +{ + return 116; +} + + +/************************************************************************* +// +**************************************************************************/ + +bool PackLinuxI386::canPack() +{ + if (exetype != 0) + return super::canPack(); + + Elf_LE32_Ehdr ehdr; + unsigned char *buf = ehdr.e_ident; + + fi->readx(&ehdr, sizeof(ehdr)); + fi->seek(0, SEEK_SET); + + exetype = 0; + const unsigned l = get_le32(buf); +#if 0 + // NOTE: ELF executables are now handled by p_lx_elf.cpp. + if (!memcmp(buf, "\x7f\x45\x4c\x46\x01\x01\x01", 7)) // ELF 32-bit LSB + { + // FIXME: add special checks for uncompresed "vmlinux" kernel + exetype = 1; + // now check the ELF header + if (!memcmp(buf+8, "FreeBSD", 7)) // branded + exetype = 0; + if (ehdr.e_type != 2) // executable + exetype = 0; + if (ehdr.e_machine != 3 && ehdr.e_machine != 6) // Intel 80[34]86 + exetype = 0; + if (ehdr.e_version != 1) // version + exetype = 0; + } + else +#endif + if (l == 0x00640107 || l == 0x00640108 || l == 0x0064010b || l == 0x006400cc) + { + // OMAGIC / NMAGIC / ZMAGIC / QMAGIC + exetype = 2; + // FIXME: N_TRSIZE, N_DRSIZE + // FIXME: check for aout shared libraries + } +#if defined(__linux__) + // only compress scripts when running under Linux + else if (!memcmp(buf, "#!/", 3)) // #!/bin/sh + exetype = -1; + else if (!memcmp(buf, "#! /", 4)) // #! /bin/sh + exetype = -1; + else if (!memcmp(buf, "\xca\xfe\xba\xbe", 4)) // Java bytecode + exetype = -2; +#endif + + return super::canPack(); +} + + +void PackLinuxI386::patchLoader() +{ + lsize = getLoaderSize(); + + // patch loader + // note: we only can use /proc//fd when exetype > 0. + // also, we sleep much longer when compressing a script. + patch_le32(loader,lsize,"UPX4",exetype > 0 ? 3 : 15); // sleep time + patch_le32(loader,lsize,"UPX3",exetype > 0 ? 0 : 0x7fffffff); + patch_le32(loader,lsize,"UPX2",progid); + patchVersion(loader,lsize); + + Elf_LE32_Ehdr *const ehdr = (Elf_LE32_Ehdr *)(void *)loader; + Elf_LE32_Phdr *const phdr = (Elf_LE32_Phdr *)(1+ehdr); + + // stub/scripts/setfold.pl puts address of 'fold_begin' in phdr[1].p_offset + off_t const fold_begin = phdr[1].p_offset; + assert(fold_begin > 0); + assert(fold_begin < (off_t)lsize); + MemBuffer cprLoader(lsize); + + // compress compiled C-code portion of loader + upx_uint const uncLsize = lsize - fold_begin; + upx_uint cprLsize; + int r = upx_compress(loader + fold_begin, uncLsize, cprLoader, &cprLsize, + NULL, opt->method, 10, NULL, NULL); + if (r != UPX_E_OK || cprLsize >= uncLsize) + throwInternalError("loaded compression failed"); + + memcpy(fold_begin+loader, cprLoader, cprLsize); + lsize = fold_begin + cprLsize; + phdr->p_filesz = lsize; + // phdr->p_memsz is the decompressed size + + // The beginning of our loader consists of a elf_hdr (52 bytes) and + // one section elf_phdr (32 byte) now, + // another section elf_phdr (32 byte) later, so we have 12 free bytes + // from offset 116 to the program start at offset 128. + // These 12 bytes are used for l_info by ::patchLoaderChecksum(). + assert(get_le32(loader + 28) == 52); // e_phoff + assert(get_le32(loader + 32) == 0); // e_shoff + assert(get_le16(loader + 40) == 52); // e_ehsize + assert(get_le16(loader + 42) == 32); // e_phentsize + assert(get_le16(loader + 44) == 1); // e_phnum + assert(get_le16(loader + 48) == 0); // e_shnum + assert(lsize > 128 && lsize < 4096); + + patchLoaderChecksum(); +} + + +void PackLinuxI386::patchLoaderChecksum() +{ + l_info *const lp = (l_info *)(loader + getLoaderPrefixSize()); + // checksum for loader + p_info + lp->l_checksum = 0; // (this checksum is currently unused) + lp->l_magic = UPX_ELF_MAGIC; + lp->l_lsize = (unsigned short) lsize; + lp->l_version = (unsigned char) ph.version; + lp->l_format = (unsigned char) ph.format; + unsigned adler = upx_adler32(0,NULL,0); + adler = upx_adler32(adler, loader, lsize + sizeof(p_info)); + lp->l_checksum = adler; +} + + +void PackLinuxI386::updateLoader(OutputFile *fo) +{ +#define PAGE_MASK (~0<<12) + Elf_LE32_Ehdr *ehdr = (Elf_LE32_Ehdr *)(unsigned char *)loader; + ehdr->e_phnum = 2; + + // The first Phdr maps the stub (instructions, data, bss) rwx. + // The second Phdr maps the overlay r--, + // to defend against /usr/bin/strip removing the overlay. + Elf_LE32_Phdr *const phdro = 1+(Elf_LE32_Phdr *)(1+ehdr); + + phdro->p_type = PT_LOAD; + phdro->p_offset = lsize; + phdro->p_paddr = phdro->p_vaddr = 0x00400000 + (lsize &~ PAGE_MASK); + phdro->p_memsz = phdro->p_filesz = fo->getBytesWritten() - lsize; + phdro->p_flags = PF_R; + phdro->p_align = -PAGE_MASK; + + patchLoaderChecksum(); + fo->seek(0, SEEK_SET); + fo->rewrite(loader, 0x80); +#undef PAGE_MASK +} + + +/* +vi:ts=4:et +*/ + diff --git a/src/p_lx_exc.h b/src/p_lx_exc.h new file mode 100644 index 00000000..f37c39e1 --- /dev/null +++ b/src/p_lx_exc.h @@ -0,0 +1,69 @@ +/* p_lx_exc.h -- + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996-2000 Laszlo Molnar + All Rights Reserved. + + UPX and the UCL library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer Laszlo Molnar + markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu + */ + + +#ifndef __UPX_P_LX_EXC_H +#define __UPX_P_LX_EXC_H + + +/************************************************************************* +// linux/386 (generic "execve" format) +**************************************************************************/ + +class PackLinuxI386 : public PackUnixLe32 +{ + typedef PackUnixLe32 super; +public: + PackLinuxI386(InputFile *f) : super(f) { } + virtual int getFormat() const { return UPX_F_LINUX_i386; } + virtual const char *getName() const { return "linux/386"; } + virtual int getCompressionMethod() const; + + virtual bool canPack(); + +protected: + virtual const upx_byte *getLoader() const; + virtual int getLoaderSize() const; + virtual int getLoaderPrefixSize() const; + + virtual void patchLoader(); + virtual void patchLoaderChecksum(); + virtual void updateLoader(OutputFile *); + + enum { + UPX_ELF_MAGIC = 0x5850557f // "\x7fUPX" + }; +}; + + +#endif /* already included */ + + +/* +vi:ts=4:et +*/ + diff --git a/src/p_lx_sep.cpp b/src/p_lx_sep.cpp index 37be0f9e..17f1a769 100644 --- a/src/p_lx_sep.cpp +++ b/src/p_lx_sep.cpp @@ -36,6 +36,7 @@ #include "packer.h" #include "p_elf.h" #include "p_unix.h" +#include "p_lx_exc.h" #include "p_lx_elf.h" #include "p_lx_sep.h" diff --git a/src/p_lx_sh.cpp b/src/p_lx_sh.cpp index a711f3ab..c8f7f2ff 100644 --- a/src/p_lx_sh.cpp +++ b/src/p_lx_sh.cpp @@ -36,6 +36,7 @@ #include "packer.h" #include "p_elf.h" #include "p_unix.h" +#include "p_lx_exc.h" #include "p_lx_sh.h" static const diff --git a/src/p_unix.cpp b/src/p_unix.cpp index c6db5aa8..b8617db2 100644 --- a/src/p_unix.cpp +++ b/src/p_unix.cpp @@ -322,198 +322,6 @@ void PackUnix::unpack(OutputFile *fo) } -/************************************************************************* -// linux/i386 (generic "execve" format) -**************************************************************************/ - -static const -#include "stub/l_lx_n2b.h" -static const -#include "stub/l_lx_n2d.h" - - -int PackLinuxI386::getCompressionMethod() const -{ - if (M_IS_NRV2B(opt->method)) - return M_NRV2B_LE32; - if (M_IS_NRV2D(opt->method)) - return M_NRV2D_LE32; - return opt->level > 1 && file_size >= 512*1024 ? M_NRV2D_LE32 : M_NRV2B_LE32; -} - - -const upx_byte *PackLinuxI386::getLoader() const -{ - if (M_IS_NRV2B(opt->method)) - return linux_i386exec_nrv2b_loader; - if (M_IS_NRV2D(opt->method)) - return linux_i386exec_nrv2d_loader; - return NULL; -} - - -int PackLinuxI386::getLoaderSize() const -{ - if (0!=lsize) { - return lsize; - } - if (M_IS_NRV2B(opt->method)) - return sizeof(linux_i386exec_nrv2b_loader); - if (M_IS_NRV2D(opt->method)) - return sizeof(linux_i386exec_nrv2d_loader); - return 0; -} - - -int PackLinuxI386::getLoaderPrefixSize() const -{ - return 116; -} - - -bool PackLinuxI386::canPack() -{ - if (exetype != 0) - return super::canPack(); - - Elf_LE32_Ehdr ehdr; - unsigned char *buf = ehdr.e_ident; - - fi->readx(&ehdr, sizeof(ehdr)); - fi->seek(0, SEEK_SET); - - exetype = 0; - const unsigned l = get_le32(buf); -#if 0 - // NOTE: ELF executables are now handled by p_lx_elf.cpp. - if (!memcmp(buf, "\x7f\x45\x4c\x46\x01\x01\x01", 7)) // ELF 32-bit LSB - { - // FIXME: add special checks for uncompresed "vmlinux" kernel - exetype = 1; - // now check the ELF header - if (!memcmp(buf+8, "FreeBSD", 7)) // branded - exetype = 0; - if (ehdr.e_type != 2) // executable - exetype = 0; - if (ehdr.e_machine != 3 && ehdr.e_machine != 6) // Intel 80[34]86 - exetype = 0; - if (ehdr.e_version != 1) // version - exetype = 0; - } - else -#endif - if (l == 0x00640107 || l == 0x00640108 || l == 0x0064010b || l == 0x006400cc) - { - // OMAGIC / NMAGIC / ZMAGIC / QMAGIC - exetype = 2; - // FIXME: N_TRSIZE, N_DRSIZE - // FIXME: check for aout shared libraries - } -#if defined(__linux__) - // only compress scripts when running under Linux - else if (!memcmp(buf, "#!/", 3)) // #!/bin/sh - exetype = -1; - else if (!memcmp(buf, "#! /", 4)) // #! /bin/sh - exetype = -1; - else if (!memcmp(buf, "\xca\xfe\xba\xbe", 4)) // Java bytecode - exetype = -2; -#endif - - return super::canPack(); -} - - -void PackLinuxI386::patchLoader() -{ - lsize = getLoaderSize(); - - // patch loader - // note: we only can use /proc//fd when exetype > 0. - // also, we sleep much longer when compressing a script. - patch_le32(loader,lsize,"UPX4",exetype > 0 ? 3 : 15); // sleep time - patch_le32(loader,lsize,"UPX3",exetype > 0 ? 0 : 0x7fffffff); - patch_le32(loader,lsize,"UPX2",progid); - patchVersion(loader,lsize); - - Elf_LE32_Ehdr *const ehdr = (Elf_LE32_Ehdr *)(void *)loader; - Elf_LE32_Phdr *const phdr = (Elf_LE32_Phdr *)(1+ehdr); - - // stub/scripts/setfold.pl puts address of 'fold_begin' in phdr[1].p_offset - off_t const fold_begin = phdr[1].p_offset; - assert(fold_begin > 0); - assert(fold_begin < (off_t)lsize); - MemBuffer cprLoader(lsize); - - // compress compiled C-code portion of loader - upx_uint const uncLsize = lsize - fold_begin; - upx_uint cprLsize; - int r = upx_compress(loader + fold_begin, uncLsize, cprLoader, &cprLsize, - NULL, opt->method, 10, NULL, NULL); - if (r != UPX_E_OK || cprLsize >= uncLsize) - throwInternalError("loaded compression failed"); - - memcpy(fold_begin+loader, cprLoader, cprLsize); - lsize = fold_begin + cprLsize; - phdr->p_filesz = lsize; - // phdr->p_memsz is the decompressed size - - // The beginning of our loader consists of a elf_hdr (52 bytes) and - // one section elf_phdr (32 byte) now, - // another section elf_phdr (32 byte) later, so we have 12 free bytes - // from offset 116 to the program start at offset 128. - // These 12 bytes are used for l_info by ::patchLoaderChecksum(). - assert(get_le32(loader + 28) == 52); // e_phoff - assert(get_le32(loader + 32) == 0); // e_shoff - assert(get_le16(loader + 40) == 52); // e_ehsize - assert(get_le16(loader + 42) == 32); // e_phentsize - assert(get_le16(loader + 44) == 1); // e_phnum - assert(get_le16(loader + 48) == 0); // e_shnum - assert(lsize > 128 && lsize < 4096); - - patchLoaderChecksum(); -} - - -void PackLinuxI386::patchLoaderChecksum() -{ - l_info *const lp = (l_info *)(loader + getLoaderPrefixSize()); - // checksum for loader + p_info - lp->l_checksum = 0; // (this checksum is currently unused) - lp->l_magic = UPX_ELF_MAGIC; - lp->l_lsize = (unsigned short) lsize; - lp->l_version = (unsigned char) ph.version; - lp->l_format = (unsigned char) ph.format; - unsigned adler = upx_adler32(0,NULL,0); - adler = upx_adler32(adler, loader, lsize + sizeof(p_info)); - lp->l_checksum = adler; -} - - -void PackLinuxI386::updateLoader(OutputFile *fo) -{ -#define PAGE_MASK (~0<<12) - Elf_LE32_Ehdr *ehdr = (Elf_LE32_Ehdr *)(unsigned char *)loader; - ehdr->e_phnum = 2; - - // The first Phdr maps the stub (instructions, data, bss) rwx. - // The second Phdr maps the overlay r--, - // to defend against /usr/bin/strip removing the overlay. - Elf_LE32_Phdr *const phdro = 1+(Elf_LE32_Phdr *)(1+ehdr); - - phdro->p_type = PT_LOAD; - phdro->p_offset = lsize; - phdro->p_paddr = phdro->p_vaddr = 0x00400000 + (lsize &~ PAGE_MASK); - phdro->p_memsz = phdro->p_filesz = fo->getBytesWritten() - lsize; - phdro->p_flags = PF_R; - phdro->p_align = -PAGE_MASK; - - patchLoaderChecksum(); - fo->seek(0, SEEK_SET); - fo->rewrite(loader, 0x80); -#undef PAGE_MASK -} - - /* vi:ts=4:et */ diff --git a/src/p_unix.h b/src/p_unix.h index 1684569d..98108f65 100644 --- a/src/p_unix.h +++ b/src/p_unix.h @@ -126,36 +126,6 @@ protected: }; -/************************************************************************* -// linux/i386 (generic "execve" format) -**************************************************************************/ - -class PackLinuxI386 : public PackUnixLe32 -{ - typedef PackUnixLe32 super; -public: - PackLinuxI386(InputFile *f) : super(f) { } - virtual int getFormat() const { return UPX_F_LINUX_i386; } - virtual const char *getName() const { return "linux/386"; } - virtual int getCompressionMethod() const; - - virtual bool canPack(); - -protected: - virtual const upx_byte *getLoader() const; - virtual int getLoaderSize() const; - virtual int getLoaderPrefixSize() const; - - virtual void patchLoader(); - virtual void patchLoaderChecksum(); - virtual void updateLoader(OutputFile *); - - enum { - UPX_ELF_MAGIC = 0x5850557f // "\x7fUPX" - }; -}; - - /************************************************************************* // solaris/sparc **************************************************************************/ diff --git a/src/packmast.cpp b/src/packmast.cpp index 9254801d..d2ba255f 100644 --- a/src/packmast.cpp +++ b/src/packmast.cpp @@ -34,8 +34,9 @@ #include "p_com.h" #include "p_djgpp2.h" #include "p_exe.h" -#include "p_elf.h" #include "p_unix.h" +#include "p_elf.h" +#include "p_lx_exc.h" #include "p_lx_elf.h" #include "p_lx_sep.h" #include "p_lx_sh.h"