C 系统的正确内联汇编代码

C 系统的正确内联汇编代码,c,x86,freebsd,inline-assembly,i386,C,X86,Freebsd,Inline Assembly,I386,我已经为系统调用sys_uname编写了内联汇编代码,但它似乎不正确 #include <sys/utsname.h> #include <stdio.h> #include <stdlib.h> #include <sys/syscalls.h> #include <string.h> struct utsname stroj; __asm__ volatile("pushl $0;" "pushl %%

我已经为系统调用sys_uname编写了内联汇编代码,但它似乎不正确

#include <sys/utsname.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/syscalls.h>
#include <string.h>

struct utsname stroj;
__asm__ volatile("pushl $0;"
              "pushl %%ebx;"
              "pushl $0;"
              "int $0x80;"
              :
              : "a" (SYS_uname), "b" (&stroj)
              );

//uname(&stroj); -> when I do this it works, but again, I want to use inline assembly
write(1, stroj.nodename, strlen(stroj.nodename)); // 1 = stdout
#包括
#包括
#包括
#包括
#包括
结构utsname stroj;
__asm_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
“PUSH%%ebx;”
“pushl$0;”
“整型$0x80;”
:
:“a”(SYS_uname),“b”(&stroj)
);
//uname(&stroj);->当我这样做的时候,它是有效的,但同样,我想使用内联汇编
写入(1,stroj.nodename,strlen(stroj.nodename));//1=标准输出

是否有一些我没有解决的突出问题?这个答案假设您希望直接使用系统调用而不是通过C库函数使用系统调用是有原因的

正确的内联程序集版本可能如下所示:

#include <sys/utsname.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <string.h>
#include <unistd.h>

/* SYS_uname has the value 164 */
/* #define SYS_uname 164 */

#define SYS_uname SYS_freebsd4_uname

int main()
{
    u_int syscallnum = SYS_uname;
    struct utsname stroj;

    asm("push %[stroj]\n\t"
        "push %%eax\n\t"        /* Required dummy value for int 0x80 */
        "int $0x80\n\t"
        "add $8, %%esp"         /* 2*4 bytes removed from stack */
        : "+a"(syscallnum)      /* error code also returned in syscallnum */
        : [stroj]"r"(&stroj)
        : "memory");

    write(1, stroj.nodename, strlen(stroj.nodename));
    return 0;
}

FreeBSD 2+不支持过时的系统 如果你尝试运行上面的代码,你会发现它没有返回任何东西。如果将该程序与类似
truss./progname
的命令一起使用,您应该会在输出中看到类似的内容:

obs#u uname(0xffffc6f8,0x0,0x0,0x0,0x0)错误#78“未实现函数”

这是因为,现在被认为是过时的。FreeBSD的libc
uname
调用以填充
utsname
结构的字段。在命令行中,您可以使用以下命令查询
节点名

sysctl kern.hostname
您可以通过以下方式通过系统调用调用
sysctl

#include <unistd.h>
#include <sys/syscall.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/sysctl.h>

#define OSNAME_MAX_LEN 256
/* SYS___sysctl has the value 202 */
/* #define SYS___sysctl 202 */

int main(void)
{
    char        osname[OSNAME_MAX_LEN];
    size_t      osnamelen = sizeof(osname) - 1;
    int         name[] = {CTL_KERN, KERN_HOSTNAME};
    u_int       namelen = sizeof(name) / sizeof(name[0]);
    char *      old = osname;
    size_t *    oldlenp = &osnamelen;

    u_int syscallnum = SYS___sysctl;

    asm("push %[newlen]\n\t"
        "push %[new]\n\t"
        "push %[oldlenp]\n\t"
        "push %[old]\n\t"
        "push %[namelen]\n\t"
        "push %[name]\n\t"
        "push %%eax\n\t"         /* Required dummy value */
        "int $0x80\n\t"
        "add $28, %%esp"         /* 7*4=28 bytes to remove from stack */
        : "+a"(syscallnum)       /* error code also returned in syscallnum */
        : [name]"r"(name), [namelen]"r"(namelen),
          [old]"r"(old)  , [oldlenp]"r"(oldlenp),
          [new]"i"(NULL), [newlen]"i"(0)
        : "memory");

    if (syscallnum) {
        return EXIT_FAILURE;
    }

    osname[osnamelen]='\0';     /* Ensure the OS Name is Null terminated */
    printf("This machine's node name is %s\n", osname);
    return EXIT_SUCCESS;
}
#include <unistd.h>
#include <sys/syscall.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/sysctl.h>

#define OSNAME_MAX_LEN 256
/* SYS___sysctl has the value 202 */
/* #define SYS___sysctl 202 */

int main(void)
{
    char        osname[OSNAME_MAX_LEN];
    size_t      osnamelen = sizeof(osname) - 1;
    int         name[] = {CTL_KERN, KERN_HOSTNAME};
    u_int       namelen = sizeof(name) / sizeof(name[0]);
    char *      old = osname;
    size_t *    oldlenp = &osnamelen;

    if (syscall(SYS___sysctl, name, namelen, old, oldlenp, NULL, 0) == -1) {
        perror("sysctl");
        return EXIT_FAILURE;
    }

    osname[osnamelen]='\0';     /* Ensure the OS Name is Null terminated */
    printf("This machine's node name is %s\n", osname);
    return EXIT_SUCCESS;
}

两次超过0美元可能是错误的。也许其中一个应该是1.5美元,可以编辑,可以编译。我还试着用$1替换$0,输出没有变化。其中一个应该是你问题的答案我希望这是OSX的?你为什么要在堆栈上加零?好的,是的,i386 FreeBSD在用户空间堆栈上传递syscall参数。另外,您忘记了一个
“memory”
clobber或内存输出操作数,因此编译器将假定
stroj
仍然没有修改,并且可以在编译时计算
strlen
。您是否尝试使用
strace
或类似工具跟踪系统调用?我没有使用strace的经验,这是我第一次尝试内联汇编。我将添加内存缓冲。
#include <unistd.h>
#include <sys/syscall.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/sysctl.h>

#define OSNAME_MAX_LEN 256
/* SYS___sysctl has the value 202 */
/* #define SYS___sysctl 202 */

int main(void)
{
    char        osname[OSNAME_MAX_LEN];
    size_t      osnamelen = sizeof(osname) - 1;
    int         name[] = {CTL_KERN, KERN_HOSTNAME};
    u_int       namelen = sizeof(name) / sizeof(name[0]);
    char *      old = osname;
    size_t *    oldlenp = &osnamelen;

    if (syscall(SYS___sysctl, name, namelen, old, oldlenp, NULL, 0) == -1) {
        perror("sysctl");
        return EXIT_FAILURE;
    }

    osname[osnamelen]='\0';     /* Ensure the OS Name is Null terminated */
    printf("This machine's node name is %s\n", osname);
    return EXIT_SUCCESS;
}