diff mbox series

[v4] Fixes pseudo build in loongarch64

Message ID 20230530113302.1473632-1-zhangjialing@loongson.cn
State New
Headers show
Series [v4] Fixes pseudo build in loongarch64 | expand

Commit Message

张家岭 May 30, 2023, 11:33 a.m. UTC
From: JiaLing Zhang <zhangjialing@loongson.cn>

Fixes [YOCTO #15110]

Some functions used in the project have been removed from glibc. After the removal of these functions,
the architecture in glibc will not include the removed functions.
This patch resolves the usage and compilation issues on the loongarch64 architecture

Signed-off-by: JiaLing Zhang <zhangjialing@loongson.cn>
---
 ports/linux/guts/fopen64.c    | 14 +++++--
 ports/linux/guts/freopen64.c  |  8 ++++
 ports/linux/guts/fstat.c      | 11 +++++-
 ports/linux/guts/fstat64.c    | 16 ++++++++
 ports/linux/guts/fstatat.c    |  8 +++-
 ports/linux/guts/fstatat64.c  | 43 +++++++++++++++++++++
 ports/linux/guts/lstat.c      |  5 ++-
 ports/linux/guts/lstat64.c    |  5 ++-
 ports/linux/guts/mknod.c      |  4 ++
 ports/linux/guts/mknodat.c    | 72 +++++++++++++++++++++++++++++++++++
 ports/linux/guts/mkostemp64.c |  4 ++
 ports/linux/guts/openat.c     | 36 ++++++++++++++++++
 ports/linux/guts/stat.c       |  5 ++-
 ports/linux/guts/stat64.c     |  5 ++-
 ports/linux/pseudo_wrappers.c | 32 ++++++++++++++++
 pseudo_client.h               |  8 ++++
 templates/wrapfuncs.c         |  2 +
 17 files changed, 268 insertions(+), 10 deletions(-)

Comments

Michael Opdenacker May 30, 2023, 11:53 a.m. UTC | #1
Hi JiaLing

On 30.05.23 at 13:33, zhangjialing@loongson.cn wrote:
> From: JiaLing Zhang <zhangjialing@loongson.cn>
>
> Fixes [YOCTO #15110]
>
> Some functions used in the project have been removed from glibc. After the removal of these functions,
> the architecture in glibc will not include the removed functions.
> This patch resolves the usage and compilation issues on the loongarch64 architecture
>
> Signed-off-by: JiaLing Zhang <zhangjialing@loongson.cn>


The patch looks perfect, thanks!
I trust you on the contents ;-)
Cheers
Michael.
Richard Purdie May 30, 2023, 12:23 p.m. UTC | #2
On Tue, 2023-05-30 at 19:33 +0800, zhangjialing@loongson.cn wrote:
> From: JiaLing Zhang <zhangjialing@loongson.cn>
> 
> Fixes [YOCTO #15110]
> 
> Some functions used in the project have been removed from glibc. After the removal of these functions,
> the architecture in glibc will not include the removed functions.
> This patch resolves the usage and compilation issues on the loongarch64 architecture

Whilst this might make things compile, I'm not convinced this is right.
I suspect that with this patch applied, you'd miss intercepting some
function calls that need intercepting.

As far as I can tell, the __fxstat64() function and friends should
exist even on a new architecture like loongarch64. Are you sure these
don't exist in a loongarch64 glibc?

Cheers,

Richard
Seebs May 30, 2023, 4:43 p.m. UTC | #3
On Tue, 30 May 2023 19:33:03 +0800
zhangjialing@loongson.cn wrote:

> +#ifdef __loongarch64

No.

Use the configuration mechanisms or whatever to determine the *actual
distinction you care about*, which is "does glibc have __xstat64", give
that a name, and use the name.

Some day, someone else will make a glibc that doesn't have __xstat64.
The change to adopt that should be one line in configure or the like,
not hundreds of changes scattered throughout the code.

> +        int existed = (real_stat64(path, &buf) != -1);
> +#else
>  	int existed = (real___xstat64(_STAT_VER, path, &buf) != -1);
> -
> +#endif

This looks suspiciously similar to the logic you introduce elsewhere
for base_stat, base_fstat, etcetera.

Reproducing that up here:

> +#ifdef __loongarch64
> +#define base_fstatat(dirfd, path, buf, flags) real_fstatat64( dirfd,
> path, buf, flags)
> +#else
>  #define base_fstatat(dirfd, path, buf, flags)
> real___fxstatat64(_STAT_VER, dirfd, path, buf, flags)
> +#endif

Again, shouldn't be using a specific arch flag, should be using a
symbolic flag, but: Given this, maybe we should just be using
base_fstatat, base_stat, etcetera, in these lines, rather than
calling a specific real___foo function directly. Or alternatively,
we should be using pseudo_stat, etcetera, which also exist, and
I honestly don't remember why there are two sets of those.

So the change should look something like

- int existed = ((real___xstat64(_STAT_VER, path, &buf) != -1);
+ int existed = ((base_stat(path, &buf) != -1);

with suitable updates to the way we define the base_foo functions,
making them contingent on something like HAVE_XSTAT.

This would cover the vast majority of these changes, but not all of
them.

> --- a/ports/linux/guts/fstat.c
> +++ b/ports/linux/guts/fstat.c
> @@ -7,8 +7,17 @@
>   * int fstat(int fd, struct stat *buf)
>   *	int rc = -1;
>   */
> -
> +#ifdef __loongarch64
> +	struct stat64 buf64;
> +        /* populate buffer with complete data */
> +	real_fstat(fd, buf);
> +        /* obtain fake data */
> +	rc = wrap_fstat64(fd, &buf64);
> +        /* overwrite */
> +	pseudo_stat32_from64(buf, &buf64);
> +#else
>  	rc = wrap___fxstat(_STAT_VER, fd, buf);
> +#endif
>  
>  /*	return rc;
>   * }

Here, we really do have a meaningful change; in the standard linux port,
we know that we can just forward fstat to __fxstat.

Probably the best model for the canonical way to fix this is to look
at the oldclone/newclone subports. When you have changes this
substantive, we don't want to do them with large inline #ifdefs; we want
to describe these as distinct subports, which have a different set of
functions. So in the hypothetical new "xstat" port, we'd have the
existing fstat and __fxstat wrappers, and in the new "noxstat" port,
we'd just have an fstat wrapper that uses the same logic.

> diff --git a/templates/wrapfuncs.c b/templates/wrapfuncs.c
> index 93bb671..14a42e2 100644
> --- a/templates/wrapfuncs.c
> +++ b/templates/wrapfuncs.c
> @@ -13,7 +13,9 @@
>   * script if you want to modify this. */
>  @body
>  
> +#ifndef __loongarch64
>  static ${type} (*real_${name})(${decl_args}) = ${real_init};
> +#endif
>  
>  ${maybe_skip}

I don't understand how this part can work at all; I was under the
impression that we actually did in fact use these real_foo objects,
and this seems to remove them all, so I don't even get how this
is compiling or running, because after this, there's no real_foo
function pointers at all?

Unfortunately, it turns out bitrot has taken my laptop and I can't
build pseudo on it natively because _STAT_VER no longer exists. So
I think the hypothetical distant future in which we conceivably
care about a system on which the real___xstatat(_STAT_VER, ...) calls
fail and isn't __longarch64 actually happened over a year ago and
we just didn't notice.

"Oops."

-s
Mark Hatle May 30, 2023, 9:44 p.m. UTC | #4
I am working on changing the v4 into a more generic implementation based on 
Seebs' and others comments.  I'll likely be sending something to the list as an 
RFC later today or tomorrow.

--Mark

On 5/30/23 11:43 AM, Seebs wrote:
> On Tue, 30 May 2023 19:33:03 +0800
> zhangjialing@loongson.cn wrote:
> 
>> +#ifdef __loongarch64
> 
> No.
> 
> Use the configuration mechanisms or whatever to determine the *actual
> distinction you care about*, which is "does glibc have __xstat64", give
> that a name, and use the name.
> 
> Some day, someone else will make a glibc that doesn't have __xstat64.
> The change to adopt that should be one line in configure or the like,
> not hundreds of changes scattered throughout the code.
> 
>> +        int existed = (real_stat64(path, &buf) != -1);
>> +#else
>>   	int existed = (real___xstat64(_STAT_VER, path, &buf) != -1);
>> -
>> +#endif
> 
> This looks suspiciously similar to the logic you introduce elsewhere
> for base_stat, base_fstat, etcetera.
> 
> Reproducing that up here:
> 
>> +#ifdef __loongarch64
>> +#define base_fstatat(dirfd, path, buf, flags) real_fstatat64( dirfd,
>> path, buf, flags)
>> +#else
>>   #define base_fstatat(dirfd, path, buf, flags)
>> real___fxstatat64(_STAT_VER, dirfd, path, buf, flags)
>> +#endif
> 
> Again, shouldn't be using a specific arch flag, should be using a
> symbolic flag, but: Given this, maybe we should just be using
> base_fstatat, base_stat, etcetera, in these lines, rather than
> calling a specific real___foo function directly. Or alternatively,
> we should be using pseudo_stat, etcetera, which also exist, and
> I honestly don't remember why there are two sets of those.
> 
> So the change should look something like
> 
> - int existed = ((real___xstat64(_STAT_VER, path, &buf) != -1);
> + int existed = ((base_stat(path, &buf) != -1);
> 
> with suitable updates to the way we define the base_foo functions,
> making them contingent on something like HAVE_XSTAT.
> 
> This would cover the vast majority of these changes, but not all of
> them.
> 
>> --- a/ports/linux/guts/fstat.c
>> +++ b/ports/linux/guts/fstat.c
>> @@ -7,8 +7,17 @@
>>    * int fstat(int fd, struct stat *buf)
>>    *	int rc = -1;
>>    */
>> -
>> +#ifdef __loongarch64
>> +	struct stat64 buf64;
>> +        /* populate buffer with complete data */
>> +	real_fstat(fd, buf);
>> +        /* obtain fake data */
>> +	rc = wrap_fstat64(fd, &buf64);
>> +        /* overwrite */
>> +	pseudo_stat32_from64(buf, &buf64);
>> +#else
>>   	rc = wrap___fxstat(_STAT_VER, fd, buf);
>> +#endif
>>   
>>   /*	return rc;
>>    * }
> 
> Here, we really do have a meaningful change; in the standard linux port,
> we know that we can just forward fstat to __fxstat.
> 
> Probably the best model for the canonical way to fix this is to look
> at the oldclone/newclone subports. When you have changes this
> substantive, we don't want to do them with large inline #ifdefs; we want
> to describe these as distinct subports, which have a different set of
> functions. So in the hypothetical new "xstat" port, we'd have the
> existing fstat and __fxstat wrappers, and in the new "noxstat" port,
> we'd just have an fstat wrapper that uses the same logic.
> 
>> diff --git a/templates/wrapfuncs.c b/templates/wrapfuncs.c
>> index 93bb671..14a42e2 100644
>> --- a/templates/wrapfuncs.c
>> +++ b/templates/wrapfuncs.c
>> @@ -13,7 +13,9 @@
>>    * script if you want to modify this. */
>>   @body
>>   
>> +#ifndef __loongarch64
>>   static ${type} (*real_${name})(${decl_args}) = ${real_init};
>> +#endif
>>   
>>   ${maybe_skip}
> 
> I don't understand how this part can work at all; I was under the
> impression that we actually did in fact use these real_foo objects,
> and this seems to remove them all, so I don't even get how this
> is compiling or running, because after this, there's no real_foo
> function pointers at all?
> 
> Unfortunately, it turns out bitrot has taken my laptop and I can't
> build pseudo on it natively because _STAT_VER no longer exists. So
> I think the hypothetical distant future in which we conceivably
> care about a system on which the real___xstatat(_STAT_VER, ...) calls
> fail and isn't __longarch64 actually happened over a year ago and
> we just didn't notice.
> 
> "Oops."
> 
> -s
> 
> 
> 
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#181938): https://lists.openembedded.org/g/openembedded-core/message/181938
> Mute This Topic: https://lists.openembedded.org/mt/99217464/3616948
> Group Owner: openembedded-core+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [mark.hatle@kernel.crashing.org]
> -=-=-=-=-=-=-=-=-=-=-=-
>
张家岭 May 31, 2023, 6:34 a.m. UTC | #5
Hi,

I'm sure in a loongarch64 glibc  don't  has these functions . We can 
find the libc.abilist file in the glibc  source code .

I found no __fxstat in loongarch

eg:```

➜  glibc git:(master) cat 
./sysdeps/unix/sysv/linux/x86_64/64/libc.abilist |grep __fx
GLIBC_2.2.5 __fxstat F
GLIBC_2.2.5 __fxstat64 F
GLIBC_2.4 __fxstatat F
GLIBC_2.4 __fxstatat64 F
➜  glibc git:(master) cat 
./sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist|grep __fx
```

在 2023/5/30 20:23, Richard Purdie 写道:
> On Tue, 2023-05-30 at 19:33 +0800, zhangjialing@loongson.cn wrote:
>> From: JiaLing Zhang <zhangjialing@loongson.cn>
>>
>> Fixes [YOCTO #15110]
>>
>> Some functions used in the project have been removed from glibc. After the removal of these functions,
>> the architecture in glibc will not include the removed functions.
>> This patch resolves the usage and compilation issues on the loongarch64 architecture
> Whilst this might make things compile, I'm not convinced this is right.
> I suspect that with this patch applied, you'd miss intercepting some
> function calls that need intercepting.
>
> As far as I can tell, the __fxstat64() function and friends should
> exist even on a new architecture like loongarch64. Are you sure these
> don't exist in a loongarch64 glibc?
>
> Cheers,
>
> Richard
diff mbox series

Patch

diff --git a/ports/linux/guts/fopen64.c b/ports/linux/guts/fopen64.c
index e76da69..db522a4 100644
--- a/ports/linux/guts/fopen64.c
+++ b/ports/linux/guts/fopen64.c
@@ -8,11 +8,13 @@ 
  * wrap_fopen64(const char *path, const char *mode) {
  *	FILE * rc = 0;
  */
- 	struct stat64 buf;
-	int save_errno;
-
+        struct stat64 buf;
+        int save_errno;
+#ifdef __loongarch64
+        int existed = (real_stat64(path, &buf) != -1);
+#else
 	int existed = (real___xstat64(_STAT_VER, path, &buf) != -1);
-
+#endif
 	rc = real_fopen64(path, mode);
 	save_errno = errno;
 
@@ -20,7 +22,11 @@ 
 		int fd = fileno(rc);
 
 		pseudo_debug(PDBGF_FILE, "fopen64 '%s': fd %d <FILE %p>\n", path, fd, (void *) rc);
+#ifdef __loongarch64
+		if (real_fstat64( fd, &buf) != -1) {
+#else
 		if (real___fxstat64(_STAT_VER, fd, &buf) != -1) {
+#endif
 			if (!existed) {
 				real_fchmod(fd, PSEUDO_FS_MODE(0666 & ~pseudo_umask, 0));
 				pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf);
diff --git a/ports/linux/guts/freopen64.c b/ports/linux/guts/freopen64.c
index 5fc9073..f249682 100644
--- a/ports/linux/guts/freopen64.c
+++ b/ports/linux/guts/freopen64.c
@@ -10,7 +10,11 @@ 
  */
  	struct stat64 buf;
 	int save_errno;
+#ifdef __loongarch64
+	int existed = (real_stat64(path, &buf) != -1);
+#else
 	int existed = (real___xstat64(_STAT_VER, path, &buf) != -1);
+#endif
 
 	rc = real_freopen64(path, mode, stream);
 	save_errno = errno;
@@ -19,7 +23,11 @@ 
 		int fd = fileno(rc);
 
 		pseudo_debug(PDBGF_FILE, "freopen64 '%s': fd %d\n", path, fd);
+#ifdef __loongarch64
+		if (real_fstat64(fd, &buf) != -1) {
+#else
 		if (real___fxstat64(_STAT_VER, fd, &buf) != -1) {
+#endif
 			if (!existed) {
 				real_fchmod(fd, PSEUDO_FS_MODE(0666 & ~pseudo_umask, 0));
 				pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf);
diff --git a/ports/linux/guts/fstat.c b/ports/linux/guts/fstat.c
index b089b15..35ef0ad 100644
--- a/ports/linux/guts/fstat.c
+++ b/ports/linux/guts/fstat.c
@@ -7,8 +7,17 @@ 
  * int fstat(int fd, struct stat *buf)
  *	int rc = -1;
  */
-
+#ifdef __loongarch64
+	struct stat64 buf64;
+        /* populate buffer with complete data */
+	real_fstat(fd, buf);
+        /* obtain fake data */
+	rc = wrap_fstat64(fd, &buf64);
+        /* overwrite */
+	pseudo_stat32_from64(buf, &buf64);
+#else
 	rc = wrap___fxstat(_STAT_VER, fd, buf);
+#endif
 
 /*	return rc;
  * }
diff --git a/ports/linux/guts/fstat64.c b/ports/linux/guts/fstat64.c
index 6dd97da..77e1a00 100644
--- a/ports/linux/guts/fstat64.c
+++ b/ports/linux/guts/fstat64.c
@@ -7,8 +7,24 @@ 
  * int fstat64(int fd, struct stat *buf)
  *	int rc = -1;
  */
+#ifdef __loongarch64
+        pseudo_msg_t *msg;
+        int save_errno;
 
+        rc = real_fstat64(fd, buf);
+        save_errno = errno;
+        if (rc == -1) {
+                return rc;
+        }
+        msg = pseudo_client_op(OP_FSTAT, 0, fd, -1, 0, buf);
+        if (msg && msg->result == RESULT_SUCCEED) {
+                pseudo_stat_msg(buf, msg);
+        }
+
+        errno = save_errno;
+#else
 	rc = wrap___fxstat64(_STAT_VER, fd, buf);
+#endif
 
 /*	return rc;
  * }
diff --git a/ports/linux/guts/fstatat.c b/ports/linux/guts/fstatat.c
index 3267641..de69662 100644
--- a/ports/linux/guts/fstatat.c
+++ b/ports/linux/guts/fstatat.c
@@ -7,8 +7,14 @@ 
  * int fstatat(int dirfd, const char *path, struct stat *buf, int flags)
  *	int rc = -1;
  */
-
+#ifdef __loongarch64
+	struct stat64 buf64;
+	real_fstatat(dirfd,path,buf,flags);
+	rc = wrap_fstatat64(dirfd, path, &buf64, flags);
+	pseudo_stat32_from64(buf, &buf64);
+#else
 	rc = wrap___fxstatat(_STAT_VER, dirfd, path, buf, flags);
+#endif
 
 /*	return rc;
  * }
diff --git a/ports/linux/guts/fstatat64.c b/ports/linux/guts/fstatat64.c
index c981e14..f61d8aa 100644
--- a/ports/linux/guts/fstatat64.c
+++ b/ports/linux/guts/fstatat64.c
@@ -8,7 +8,50 @@ 
  *	int rc = -1;
  */
 
+#ifdef __loongarch64
+        pseudo_msg_t *msg;
+        int save_errno;
+
+#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
+        if (dirfd != AT_FDCWD) {
+                errno = ENOSYS;
+                return -1;
+        }
+#endif
+        if (flags & AT_SYMLINK_NOFOLLOW) {
+#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
+                rc = real_lstat64(path, buf);
+#else
+                rc = real_fstatat64(dirfd, path, buf, flags);
+#endif
+                if (rc == -1) {
+                        return rc;
+                }
+        } else {
+#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
+                rc = real_stat64( path, buf);
+#else
+                rc = real_fstatat64(dirfd, path, buf, flags);
+#endif
+                if (rc == -1) {
+                        return rc;
+                }
+        }
+        save_errno = errno;
+
+          /* query database
+         * note that symlink canonicalizing is now automatic, so we
+         * don't need to check for a symlink on this end
+         */
+        msg = pseudo_client_op(OP_STAT, 0, -1, dirfd, path, buf);
+        if (msg && msg->result == RESULT_SUCCEED) {
+                pseudo_stat_msg(buf, msg);
+        }
+
+        errno = save_errno;
+#else
 	rc = wrap___fxstatat64(_STAT_VER, dirfd, path, buf, flags);
+#endif
 
 /*	return rc;
  * }
diff --git a/ports/linux/guts/lstat.c b/ports/linux/guts/lstat.c
index d2c4d50..da88a9b 100644
--- a/ports/linux/guts/lstat.c
+++ b/ports/linux/guts/lstat.c
@@ -7,8 +7,11 @@ 
  * int lstat(const char *path, struct stat *buf)
  *	int rc = -1;
  */
-
+#ifdef __loongarch64
+	rc = wrap_fstatat(AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
+#else
 	rc = wrap___fxstatat(_STAT_VER, AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
+#endif
 
 /*	return rc;
  * }
diff --git a/ports/linux/guts/lstat64.c b/ports/linux/guts/lstat64.c
index 43d0ce1..fbbe727 100644
--- a/ports/linux/guts/lstat64.c
+++ b/ports/linux/guts/lstat64.c
@@ -7,8 +7,11 @@ 
  * int lstat64(const char *path, struct stat *buf)
  *	int rc = -1;
  */
-
+#ifdef __loongarch64
+	rc = wrap_fstatat64( AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
+#else
 	rc = wrap___fxstatat64(_STAT_VER, AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
+#endif
 
 /*	return rc;
  * }
diff --git a/ports/linux/guts/mknod.c b/ports/linux/guts/mknod.c
index 61fd320..512e5bb 100644
--- a/ports/linux/guts/mknod.c
+++ b/ports/linux/guts/mknod.c
@@ -8,7 +8,11 @@ 
  *	int rc = -1;
  */
 
+#ifdef __loongarch64
+	rc = wrap_mknodat(AT_FDCWD, path, mode, dev);
+#else
 	rc = wrap___xmknod(_MKNOD_VER, path, mode, &dev);
+#endif
 
 /*	return rc;
  * }
diff --git a/ports/linux/guts/mknodat.c b/ports/linux/guts/mknodat.c
index a7e4293..fb8c0c0 100644
--- a/ports/linux/guts/mknodat.c
+++ b/ports/linux/guts/mknodat.c
@@ -7,8 +7,80 @@ 
  * int mknodat(int dirfd, const char *path, mode_t mode, dev_t dev)
  *	int rc = -1;
  */
+#ifdef __loongarch64
+        pseudo_msg_t *msg;
+        struct stat64 buf;
 
+        /* mask out mode bits appropriately */
+        mode = mode & ~pseudo_umask;
+        /* if you don't specify a type, assume regular file */
+        if (!(mode & S_IFMT)) {
+                mode |= S_IFREG;
+        }
+        pseudo_debug(PDBGF_FILE, "mknodat creating '%s', mode 0%o\n",
+                path ? path : "<no name>", (int) mode);
+
+        /* we don't use underlying call, so _ver is irrelevant to us */
+#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
+        if (dirfd != AT_FDCWD) {
+                errno = ENOSYS;
+                return -1;
+        }
+        rc = real_stat64( path, &buf);
+#else
+        rc = real_fstatat64( dirfd, path, &buf, AT_SYMLINK_NOFOLLOW);
+#endif
+        if (rc != -1) {
+                /* if we can stat the file, you can't mknod it */
+                errno = EEXIST;
+                return -1;
+        }
+        if (!dev) {
+                errno = EINVAL;
+                return -1;
+        }
+#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
+        rc = real_open(path, O_CREAT | O_WRONLY | O_EXCL,
+                PSEUDO_FS_MODE(mode, 0));
+#else
+        rc = real_openat(dirfd, path, O_CREAT | O_WRONLY | O_EXCL,
+                PSEUDO_FS_MODE(mode, 0));
+#endif
+        if (rc == -1) {
+                return -1;
+        }
+        real_fchmod(rc, PSEUDO_FS_MODE(mode, 0));
+        real_fstat64( rc, &buf);
+        /* mknod does not really open the file.  We don't have
+         * to use wrap_close because we've never exposed this file
+         * descriptor to the client code.
+         */
+        real_close(rc);
+
+        /* mask in the mode type bits again */
+        buf.st_mode = (PSEUDO_DB_MODE(buf.st_mode, mode) & 07777) |
+                        (mode & ~07777);
+        buf.st_rdev = dev;
+        msg = pseudo_client_op(OP_MKNOD, 0, -1, dirfd, path, &buf);
+        if (msg && msg->result != RESULT_SUCCEED) {
+                errno = EPERM;
+                rc = -1;
+   } else {
+                /* just pretend we worked */
+                rc = 0;
+        }
+        if (rc == -1) {
+                int save_errno = errno;
+#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
+                real_unlink(path);
+#else
+                real_unlinkat(dirfd, path, AT_SYMLINK_NOFOLLOW);
+#endif
+                errno = save_errno;
+        }
+#else
 	rc = wrap___xmknodat(_MKNOD_VER, dirfd, path, mode, &dev);
+#endif
 
 /*	return rc;
  * }
diff --git a/ports/linux/guts/mkostemp64.c b/ports/linux/guts/mkostemp64.c
index 502211b..41052c6 100644
--- a/ports/linux/guts/mkostemp64.c
+++ b/ports/linux/guts/mkostemp64.c
@@ -35,7 +35,11 @@ 
 	if (rc != -1) {
 		save_errno = errno;
 
+#ifdef __loongarch64
+		if (real_fstat64(rc, &buf) != -1) {
+#else
 		if (real___fxstat64(_STAT_VER, rc, &buf) != -1) {
+#endif
 			real_fchmod(rc, PSEUDO_FS_MODE(0600, 0));
 			pseudo_client_op(OP_CREAT, 0, -1, -1, tmp_template, &buf);
 			pseudo_client_op(OP_OPEN, PSA_READ | PSA_WRITE, rc, -1, tmp_template, &buf);
diff --git a/ports/linux/guts/openat.c b/ports/linux/guts/openat.c
index 656ac2b..86ad5e9 100644
--- a/ports/linux/guts/openat.c
+++ b/ports/linux/guts/openat.c
@@ -56,12 +56,24 @@ 
 		save_errno = errno;
 #ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
 		if (flags & O_NOFOLLOW) {
+#ifdef __loongarch64
+			rc = real_lstat64(path,&buf);
+#else
 			rc = real___lxstat64(_STAT_VER, path, &buf);
+#endif
 		} else {
+#ifdef __loongarch64
+			rc = real_stat64(path,&buf);
+#else
 			rc = real___xstat64(_STAT_VER, path, &buf);
+#endif
 		}
+#else
+#ifdef __loongarch64
+		rc = real_fstatat64(dirfd, path, &buf, (flags & O_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0);
 #else
 		rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, (flags & O_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0);
+#endif
 #endif
 		existed = (rc != -1);
 		if (!existed)
@@ -77,12 +89,24 @@ 
 		save_errno = errno;
 #ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
 		if (flags & O_NOFOLLOW) {
+#ifdef __loongarch64
+			rc = real_lstat64(path, &buf);
+#else
 			rc = real___lxstat64(_STAT_VER, path, &buf);
+#endif
 		} else {
+#ifdef __loongarch64
+			rc = real_stat64(path, &buf);
+#else
 			rc = real___xstat64(_STAT_VER, path, &buf);
+#endif
 		}
+#else
+#ifdef __loongarch64
+		rc = real_fstatat64(dirfd, path, &buf, (flags & O_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0);
 #else
 		rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, (flags & O_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0);
+#endif
 #endif
 		if (rc != -1 && S_ISFIFO(buf.st_mode)) {
 			overly_magic_nonblocking = 1;
@@ -135,12 +159,24 @@ 
 #endif
 #ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
 		if (flags & O_NOFOLLOW) {
+#ifdef __loongarch64
+			stat_rc = real_lstat64( path, &buf);
+#else
 			stat_rc = real___lxstat64(_STAT_VER, path, &buf);
+#endif
 		} else {
+#ifdef __loongarch64
+			stat_rc = real_stat64(path, &buf);
+#else
 			stat_rc = real___xstat64(_STAT_VER, path, &buf);
+#endif
 		}
+#else
+#ifdef __loongarch64
+		stat_rc = real_fstatat64(dirfd, path, &buf, (flags & O_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0);
 #else
 		stat_rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, (flags & O_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0);
+#endif
 #endif
 
 		pseudo_debug(PDBGF_FILE, "openat(path %s), flags %o, stat rc %d, stat mode %o\n",
diff --git a/ports/linux/guts/stat.c b/ports/linux/guts/stat.c
index f8c73f7..5a7b57b 100644
--- a/ports/linux/guts/stat.c
+++ b/ports/linux/guts/stat.c
@@ -7,8 +7,11 @@ 
  * int stat(const char *path, struct stat *buf)
  *	int rc = -1;
  */
-
+#ifdef __loongarch64
+	rc = wrap_fstatat(AT_FDCWD, path, buf, 0);
+#else
 	rc = wrap___fxstatat(_STAT_VER, AT_FDCWD, path, buf, 0);
+#endif
 
 /*	return rc;
  * }
diff --git a/ports/linux/guts/stat64.c b/ports/linux/guts/stat64.c
index d8b3f36..ee0583c 100644
--- a/ports/linux/guts/stat64.c
+++ b/ports/linux/guts/stat64.c
@@ -7,8 +7,11 @@ 
  * int stat64(const char *path, struct stat *buf)
  *	int rc = -1;
  */
-
+#ifdef __loongarch64
+	rc = wrap_fstatat64(AT_FDCWD, path, buf, 0);
+#else
 	rc = wrap___fxstatat64(_STAT_VER, AT_FDCWD, path, buf, 0);
+#endif
 
 /*	return rc;
  * }
diff --git a/ports/linux/pseudo_wrappers.c b/ports/linux/pseudo_wrappers.c
index 7659897..c0775b9 100644
--- a/ports/linux/pseudo_wrappers.c
+++ b/ports/linux/pseudo_wrappers.c
@@ -8,43 +8,75 @@ 
  */
 int
 pseudo_stat(const char *path, struct stat *buf) {
+#ifdef __loongarch64
+	return real_stat( path, buf);
+#else
 	return real___xstat(_STAT_VER, path, buf);
+#endif
 }
 
 int
 pseudo_lstat(const char *path, struct stat *buf) {
+#ifdef __loongarch64
+	return real_lstat(path,buf);
+#else
 	return real___lxstat(_STAT_VER, path, buf);
+#endif
 }
 
 int
 pseudo_fstat(int fd, struct stat *buf) {
+#ifdef __loongarch64
+	return real_fstat(fd,buf);
+#else
 	return real___fxstat(_STAT_VER, fd, buf);
+#endif
 }
 
 int
 pseudo_stat64(const char *path, struct stat64 *buf) {
+#ifdef __loongarch64
+	return real_stat64(path,buf);
+#else
 	return real___xstat64(_STAT_VER, path, buf);
+#endif
 }
 
 int
 pseudo_lstat64(const char *path, struct stat64 *buf) {
+#ifdef __loongarch64
+	return real_lstat64(path,buf);
+#else
 	return real___lxstat64(_STAT_VER, path, buf);
+#endif
 }
 
 int
 pseudo_fstat64(int fd, struct stat64 *buf) {
+#ifdef __loongarch64
+	return	real_fstat64(fd,buf);
+#else
 	return real___fxstat64(_STAT_VER, fd, buf);
+#endif
 }
 
 /* similar thing happens with mknod */
 int
 pseudo_mknod(const char *path, mode_t mode, dev_t dev) {
+#ifdef __loongarch64
+	return real_mknod(path,mode,dev);
+#else
 	return real___xmknod(_MKNOD_VER, path, mode, &dev);
+#endif
 }
 
 int
 pseudo_mknodat(int dirfd, const char *path, mode_t mode, dev_t dev) {
+#ifdef __loongarch64
+	return real_mknodat(dirfd,path,mode,dev);
+#else
 	return real___xmknodat(_MKNOD_VER, dirfd, path, mode, &dev);
+#endif
 }
 
 int pseudo_capset(cap_user_header_t hdrp, const cap_user_data_t datap) {
diff --git a/pseudo_client.h b/pseudo_client.h
index d7944ce..32dfe1a 100644
--- a/pseudo_client.h
+++ b/pseudo_client.h
@@ -14,13 +14,21 @@  extern void pseudo_client_linked_paths(const char *oldpath, const char *newpath)
 #define base_lstat real_lstat64
 #define base_fstat real_fstat64
 #define base_stat real_stat64
+#ifdef __loongarch64
+#define base_fstatat(dirfd, path, buf, flags) real_fstatat64( dirfd, path, buf, flags)
+#else
 #define base_fstatat(dirfd, path, buf, flags) real___fxstatat64(_STAT_VER, dirfd, path, buf, flags)
+#endif
 #else
 #define base_lstat real_lstat
 #define base_fstat real_fstat
 #define base_stat real_stat
+#ifdef __loongarch64
+#define base_fstatat(dirfd, path, buf, flags) real_fstatat( dirfd, path, buf, flags
+#else
 #define base_fstatat(dirfd, path, buf, flags) real___fxstatat(_STAT_VER, dirfd, path, buf, flags)
 #endif
+#endif
 extern void pseudo_antimagic(void);
 extern void pseudo_magic(void);
 extern void pseudo_client_touchuid(void);
diff --git a/templates/wrapfuncs.c b/templates/wrapfuncs.c
index 93bb671..14a42e2 100644
--- a/templates/wrapfuncs.c
+++ b/templates/wrapfuncs.c
@@ -13,7 +13,9 @@ 
  * script if you want to modify this. */
 @body
 
+#ifndef __loongarch64
 static ${type} (*real_${name})(${decl_args}) = ${real_init};
+#endif
 
 ${maybe_skip}