小编Sha*_*esh的帖子

x86_64 Linux函数和系统调用之间的ABI差异

x86_64的SysV的ABI的函数调用约定定义整数参数#4中的传递rcx寄存器.另一方面,Linux内核系统调用ABI r10用于同样的目的.所有其他参数都在函数和系统调用的相同寄存器中传递.

这会导致一些奇怪的事情.例如,检查mmapx32平台的glibc实现(存在相同的差异):

00432ce0 <__mmap>:
  432ce0:       49 89 ca                mov    %rcx,%r10
  432ce3:       b8 09 00 00 40          mov    $0x40000009,%eax
  432ce8:       0f 05                   syscall
Run Code Online (Sandbox Code Playgroud)

因此,所有的寄存器都已经到位,但我们移动rcxr10.

我想知道为什么不将syscall ABI定义为与函数调用ABI相同,考虑到它们已经非常相似.

assembly x86-64 system-calls abi linux-kernel

10
推荐指数
2
解决办法
765
查看次数

C++依赖于const引用的参数不会改变

请考虑以下代码:

void func1(const int &i);
void func2(int i);

void f()
{
  int a=12;
  func1(a);
  func2(a);
}
Run Code Online (Sandbox Code Playgroud)

用g ++ 4.6和-O3编译,我可以看到编译后重新读取函数调用之间的"a"值.将a的定义更改为"const int",编译器不会这样做,而是简单地将立即值"12"加载到edi中.如果a不是const,则同样如此,但我将func1的签名更改为按值接受.

虽然不是代码生成中的错误,但这仍然是奇怪的行为.因为func1承诺不改变a,为什么编译器的代码会根据a是否为const而改变?

编辑:一些怀疑论者声称我可能正在阅读错误的代码.上面的代码使用-S编译产生以下代码:

_Z1fv:
.LFB0:
        .cfi_startproc
        subq    $24, %rsp
        .cfi_def_cfa_offset 32
        leaq    12(%rsp), %rdi
        movl    $12, 12(%rsp)                                                          
        call    _Z5func1RKi
        movl    12(%rsp), %edi     <-- Rereading a
        call    _Z5func2i
        addq    $24, %rsp
        .cfi_def_cfa_offset 8
        ret
        .cfi_endproc                                                           
Run Code Online (Sandbox Code Playgroud)

将a更改为const会产生:

_Z1fv:
.LFB0:
        .cfi_startproc
        subq    $24, %rsp
        .cfi_def_cfa_offset 32
        leaq    12(%rsp), %rdi
        movl    $12, 12(%rsp)
        call    _Z5func1RKi
        movl    $12, %edi          <-- Use immediate value
        call    _Z5func2i …
Run Code Online (Sandbox Code Playgroud)

c++ gcc gcc4.6

8
推荐指数
1
解决办法
190
查看次数

使用unique_ptr来控制文件描述符

从理论上讲,我应该能够使用自定义指针类型和删除器来unique_ptr管理不是指针的对象.我尝试了以下代码:

#ifndef UNIQUE_FD_H
#define UNIQUE_FD_H

#include <memory>
#include <unistd.h>

struct unique_fd_deleter {
    typedef int pointer; // Internal type is a pointer

    void operator()( int fd )
    {
        close(fd);
    }
};

typedef std::unique_ptr<int, unique_fd_deleter> unique_fd;

#endif // UNIQUE_FD_H
Run Code Online (Sandbox Code Playgroud)

这不起作用(带-std=c++11参数的gcc 4.7 ).它响应以下错误:

In file included from /usr/include/c++/4.7/memory:86:0,
                 from test.cc:6:
/usr/include/c++/4.7/bits/unique_ptr.h: In instantiation of 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = int; _Dp = unique_fd_deleter]':
test.cc:22:55:   required from here
/usr/include/c++/4.7/bits/unique_ptr.h:172:2: error: invalid operands of types 'int' and 'std::nullptr_t' to binary 'operator!=' …
Run Code Online (Sandbox Code Playgroud)

c++ smart-pointers unique-ptr c++11 gcc4.7

7
推荐指数
2
解决办法
4734
查看次数

thread_local 与全局变量的初始化顺序

查:

#include <iostream>

class C {
public:
  explicit C(int id) { std::cout<<"Initialized "<<id<<"\n"; }
};
Run Code Online (Sandbox Code Playgroud)

1.cpp:

#include "C.h"

C global(1);
Run Code Online (Sandbox Code Playgroud)

2.cpp:

#include "C.h"

thread_local C thread(2);

int main() {}
Run Code Online (Sandbox Code Playgroud)

我的问题是:是否保证global会在之前初始化thread

C++ 标准在这一点上有些含糊,据我所知。它说(来自 C++17 n4659草案):

[basic.start.static] 静态初始化

作为程序启动的结果,具有静态存储持续时间的变量被初始化。作为线程执行的结果,具有线程存储持续时间的变量被初始化。

按理说,“程序启动”发生在“线程执行”之前,但由于这两个表达式仅出现在标准中的那个地方,我正在寻求实际语言律师的建议。

c++ undefined-behavior language-lawyer c++17

7
推荐指数
1
解决办法
319
查看次数

std :: set erase复杂度异常?

我试图弄清楚从std :: set中删除多个元素的复杂性.我正在使用此页面作为来源.

它声称使用迭代器擦除单个项目的复杂性是分摊O(1),但使用范围形式擦除多个项目是log(c.size())+ std :: distance(first,last)(即 - 集合大小的日志+删除的元素数量).

从面值来看,如果要擦除的元素的数量(n)远小于集合(m)中的元素的数量,则这意味着在要擦除的元素上循环并且一次擦除它们的速度更快(O(n))比用一次调用擦除它们(假设n << m)为O(log m).

显然,如果真的如此,第二种形式的内部实现只会做上述循环.

这是网站上的错误吗?规格中的错误?我只是错过了一些东西吗?

谢谢,Shachar

c++ stl time-complexity stdset

6
推荐指数
2
解决办法
3579
查看次数

posix_acl_access 和朋友的文档?

我试图弄清楚如何通过“system.posix_acl_access”的 getxattr 获取/设置文件访问信息。令人惊讶的是,谷歌搜索结果在第一页中没有这样的链接。手册页提到了这些属性,但除了说它们是标准的之外没有提供任何细节。

假设我希望实际使用它们,有没有比阅读 coreutils 源代码更好的选择?我想知道在系统下或其他情况下我可能会丢失哪些其他属性。

编辑添加: ACL 本身记录在 POSIX 1003.1e 中(可在此处下载。它是一个废弃的标准,但 Linux 实现了它,并且 coreutils(特别是 cp)使用它(至少是它的编译方式) Ubuntu),那么它是相关的,无论是否标准。

然而,这个问题与特定条目无关,而是与所有标准扩展属性的广泛列表相关(尽管从阅读源来看,Linux 上仅存在 system.posix_acl_access 和 system.posix_acl_default )。

linux posix

5
推荐指数
0
解决办法
796
查看次数

错误:"在OpenSSL 1.1.0中无效使用不完整类型'RSA {aka struct rsa_st}"

我有旧的代码,用于链接旧版本的openssl.此代码的一部分从PEM文件加载密钥,并尝试通过使用以下代码来了解此密钥是私钥还是公钥:

if( (prv->p==0 || prv->q==0) ) {
    // This is not a private key!
    throw error("No private key for decryption");
}
Run Code Online (Sandbox Code Playgroud)

使用最新版本的openssl,这(有理由)不编译:

crypto.cpp: In function ‘key* decrypt_header(file_t, RSA*)’:
crypto.cpp:158:13: error: invalid use of incomplete type ‘RSA {aka struct rsa_st}’
     if( (prv->p==0 || prv->q==0) ) {
             ^~
Run Code Online (Sandbox Code Playgroud)

我理解直接访问struct的私有成员被替换为一个函数,但我很难搞清楚哪个函数是什么.

c openssl

5
推荐指数
2
解决办法
6673
查看次数

为什么不允许非特权递归取消共享(CLONE_NEWUSER)?

我使用的是 Ubuntu 17.04。

挂载命名空间的单个非特权取消共享有效。您可以尝试使用 unshare(1) 命令:

$ unshare -m -U /bin/sh
#
Run Code Online (Sandbox Code Playgroud)

但是,不允许在取消共享中取消共享:

$ unshare -m -U /bin/sh
# unshare -m -U /bin/sh
unshare: Operation not permitted
#
Run Code Online (Sandbox Code Playgroud)

这是一个基本上执行相同操作的 C 程序:

#define _GNU_SOURCE
#include <stdio.h>
#include <sched.h>
#include <sys/mount.h>
#include <unistd.h>

int
main(int argc, char *argv[])
{
    if(unshare(CLONE_NEWUSER|CLONE_NEWNS) == -1) {
        perror("unshare");
        return -1;
    }
    if(unshare(CLONE_NEWUSER|CLONE_NEWNS) == -1) {
        perror("unshare2");
        return -1;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

为什么不允许?我在哪里可以找到有关此内容的文档?我未能在取消共享或克隆手册页以及内核取消共享文档中找到此信息。

是否有系统设置允许这样做?

我想要实现的目标:

第一次取消共享:我想用我自己的版本屏蔽系统上的一些二进制文件。

第二次取消共享:非特权 chroot。

c linux namespaces ubuntu-17.04

5
推荐指数
1
解决办法
4136
查看次数

在虚函数上使用 enable_if

#include <type_traits>

class Base {
public:
    virtual bool f() {
        return true;
    }
};

template<typename T>
class Derived : public Base {
    std::enable_if_t< std::is_copy_constructible<T>::value, bool > f() override {
        return true;
    }

    std::enable_if_t< !std::is_copy_constructible<T>::value, bool > f() override {
        return false;
    }
};
Run Code Online (Sandbox Code Playgroud)

上面的代码不能编译。由于某种原因我没能理解,编译器在 SFINAE 删除一个函数之前将这两个函数视为相同的重载。

然而,我不明白的是我如何解决这个问题。我发现的文档指出我应该在函数上使用模板。但是,这不起作用,因为该函数是虚拟的。

我尝试通过调用非虚拟函数来卸载问题,但我也无法编译:

template<typename T>
class Derived : public Base {
    virtual bool f() override {
        return f_impl();
    }

private:
    template< std::enable_if_t< std::is_copy_constructible<T>::value > = 0 >
    bool f_impl() {
        return true;
    } …
Run Code Online (Sandbox Code Playgroud)

c++ templates sfinae enable-if template-meta-programming

5
推荐指数
1
解决办法
756
查看次数

奇怪的编译器决定

我有以下代码:

enum nums {
  a
};

class cls {
public:
  cls( nums );
};

void function()
{
  cls( a );
}
Run Code Online (Sandbox Code Playgroud)

当我尝试使用gcc编译它时,我收到以下错误:

test.cpp: In function ‘void function()’:
test.cpp:12:10: error: no matching function for call to ‘cls::cls()’
test.cpp:12:10: note: candidates are:
test.cpp:7:3: note: cls::cls(nums)
test.cpp:7:3: note:   candidate expects 1 argument, 0 provided
test.cpp:5:7: note: cls::cls(const cls&)
test.cpp:5:7: note:   candidate expects 1 argument, 0 provided
make: *** [test] Error 1
Run Code Online (Sandbox Code Playgroud)

如果我用这个替换函数:

void function()
{
  cls name( a );
}
Run Code Online (Sandbox Code Playgroud)

一切正常.如果我使用带有两个参数的构造函数,它也可以工作.如果我在构造函数中添加"explicit",它就不起作用.

我得到gcc以某种方式将其解析为定义名为"a"的类型为"cls"的变量,但我不熟悉这种定义变量的语法.在我看来,这是一个定义cls类型的匿名临时变量的语句,传递"a"是参数.

用gcc …

c++ g++

4
推荐指数
2
解决办法
192
查看次数