小编Gem*_*lor的帖子

有关 .init_array 函数参数的任何文档吗?

我可以看到很多复制的知识,这些函数在 .init_array 部分注册的函数具有命令行参数 argc 和 argv,如 main(),但我无法在网上找到任何实际发布的文档来证实情况确实如此。

\n

是的,为了清楚起见,函数本身没有在 .init_array 中“声明”,但在那里声明了指向该函数的指针,“注册”该函数,并在启动期间由某个迭代器调用。问题仍然是:向我显示该迭代器传入的参数列表的一些文档。

\n

我的目的是以一种微妙但通常安全的方式从动态库中更改这些参数,因此我想在内存中找到“真正的交易”——而不是从 /proc/self/ 中。

\n

欲了解更多信息,请点击下面的链接。

\n

一些堆栈溢出知识:在 Linux 上访问 main 之外的主要参数

\n

即使是我最喜欢的 Oracle ( docs.oracle.com/cd/E23824_01/html/819-0690/chapter3-8.html ) 也只提到函数被调用,但没有承诺可能有什么参数。据我所知,与 elf 和 gcc 文档相同。

\n

在 C/C++ UB 偏执狂的土地上,理想情况下,在我继续之前,我需要确定这是已记录的行为?它存在吗?可以通过某种方式暗示吗?

\n
\n

迄今为止的评论/答案摘要:

\n

至少对于 GNU libc,此补丁发生了相关更改:BZ #974。\n https://sourceware.org/pipermail/libc-alpha/2005-July/019240.html(在 glibc\'s 中提到) ChangeLog.old/ChangeLog.16 条目 2005-04-13 HJ Lu.) \xe2\x80\x93\nIan Abbott

\n

对我来说,这表明 glbc 维护者意识到传递 argc/argv/env 的要求 - 这不是偶然的 - 并将其扩展到主 exe 注册。它还告诉我们,它在该日期之前适用于动态库。

\n

这是一个有趣的问题,这是否会约束其他 libc 实现者遵循该模式。

\n

c gcc elf

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

放置/逐段语法是否可能出现延迟的“运算符”或“过载”?

所以我们都去过那里。我有一个不错的对象,它有一个构造函数,如果对象创建正确,则该对象可以解析为true,但是它也具有其他状态,因此我可以很高兴地编写:

if (const auto& str = std::ofstream("/tmp/myfile"))
{
  str << "Oh that was easy\n";
}
Run Code Online (Sandbox Code Playgroud)

但是我真正想做的是尝试一些替代方法:

if (const std::stream& str = (std::ofstream("/tmp/myfile") || std::ofstream("/temp/myfile") || std::ofstream("./myfile")) )
{
  str << "Oh that was not so easy\n";
}
Run Code Online (Sandbox Code Playgroud)

显然不是!我可能会打开3个文件,但是将它们强制转换为“ true”布尔值,并且当然不能强制转换为std :: stream。如果我超载operator ||了流rvals,那么它将打开所有3个文件,因为忘记了延迟评估!

我知道,std :: stream也许是一个糟糕的例子,但是20页之后,我将完成对我的选项字符串处理器的说明,因此,请坚持使用std :: stream。

我期望可能是这样的:

if (const std::stream str = (std::piecewise_construct(std::ofstream,"/tmp/myfile") || std::piecewise_construct(std::ofstream,"/temp/myfile") || std::piecewise_construct(std::ofstream,"./myfile")) )
{
  str << "Oh that maybe makes sense?\n";
}
Run Code Online (Sandbox Code Playgroud)

为此,我可能需要2个重载operator ||,一个重载两个未解决的piecewise_construct并解析左侧的重载入门,而另一个重载一个rval对象在左侧,并且仅在“失败”时评估右侧”。就像是:

template<class PC2>
std::stream operator ||(std::stream&& str, …
Run Code Online (Sandbox Code Playgroud)

c++ c++11 c++20

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

底层段寄存器的线程本地实际使用

我阅读了许多文章和 S/O 答案说(在 linux x86_64 上)FS(或某些变体中的 GS)引用了一个特定于线程的页表条目,然后它给出了一个指向可共享的实际数据的指针数组数据。当线程被交换时,所有的寄存器都被切换,因此线程基页会发生变化。线程变量通过名称访问,只需要 1 个额外的指针跃点,并且引用的值可以共享给其他线程。一切都好,说得通。

事实上,如果你查看__errno_location(void)背后的函数的代码errno,你会发现类似的东西(这是来自 musl,但 gnu 并没有太大的不同):

static inline struct pthread *__pthread_self()
{
    struct pthread *self;
    __asm__ __volatile__ ("mov %%fs:0,%0" : "=r" (self) );
    return self;
}
Run Code Online (Sandbox Code Playgroud)

来自 glibc:

=> 0x7ffff6efb4c0 <__errno_location>:   endbr64
   0x7ffff6efb4c4 <__errno_location+4>: mov    0x6add(%rip),%rax        # 0x7ffff6f01fa8
   0x7ffff6efb4cb <__errno_location+11>:        add    %fs:0x0,%rax
   0x7ffff6efb4d4 <__errno_location+20>:        retq
Run Code Online (Sandbox Code Playgroud)

所以我的期望是 FS 的实际值会因每个线程而改变。例如,在调试器下, gdb: info regor p $fs,我会看到 FS 的值在不同的线程中是不同的,但没有: ds, es, fs, gs 一直都为零。

在我自己的代码中,我写了类似下面的内容并得到相同的结果 - FS 没有改变,但 TLV “有效”:

struct …
Run Code Online (Sandbox Code Playgroud)

c++ linux x86-64 thread-local-storage memory-segmentation

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

一个fork child能判断它是fork还是vfork吗?

在子进程中,有什么方法可以确定它是作为具有覆盖内存的 fork 还是作为具有共享内存的 vfork 启动的?

基本上,我们的日志引擎需要在 vfork 中更加小心(而不是记录某些类别的活动)。在 fork 中,它需要以 vfork 中没有的方式与父进程合作。我们知道如何做这两件事,但不知道如何决定。

我知道我可能会拦截 fork/vfork/clone 调用,并将 fork/vfork/mapping 状态存储为一个标志,但是如果孩子可以通过 API 调用来确定它自己的状态,这会让生活变得更简单。

额外标记:理想情况下,我还需要在库中选择任何已经完成 fork 或 vfork 的地方,然后再调用我们的代码。那怎么会发生呢?我们至少有一个库提供了类似 popen 的 API,其中在 exec 之前从 fork 子级调用客户端回调。显然,该回调的效用在 vfork 中受到显着限制。

c linux fork vfork

4
推荐指数
1
解决办法
265
查看次数

运算符重载导致无效

我的代码中有一个情况,我想通过模板调用类定义的二元运算符重载,但第二个参数可能是 void 类型。可以写这个专业吗?

原因:

所以我有一个现有的宏化/模板包装,它可以帮助我记录函数的返回值。

它有点像这样:

#define Return  return DebugPlacement({__FILE__,__LINE__}) <<= 
Run Code Online (Sandbox Code Playgroud)

其中 DebugPlacement 是一个小点类,具有模板化重载operator <<=

struct DebugPlacement
{
   const char* path; int line;

   template <class Arg>
   const Arg& operator <<= (const Arg& arg)const
   {
       std::cerr << "DIAG: " << path << ":" << line << " returns " << arg << std::endl;
       return arg;
   }

};
Run Code Online (Sandbox Code Playgroud)

我们选择运算符 <<= 是因为它相当晦涩,并且行为有点像现有的流运算符,但相反。而且它的低优先级意味着几乎任何合理的表达式都可以写在 RHS 上。

另一个妥协:所有类型通常都很简单,因此 rval 的使用不是一个大问题。我确信我们最终会在这里看到完美转发的需要,但现在还不是。

它打印该值并返回它。我可以插入各种一般专业化,因为我发现我需要它们, - char* 等。不需要额外的括号。效果非常好,谢谢您的询问!

在很多情况下,它用在 API 存根中:

extern int MyFunction(int (arg1), int (arg2));
int MyFunctionStub(int …
Run Code Online (Sandbox Code Playgroud)

c++ c++11

3
推荐指数
1
解决办法
348
查看次数

回显传递给带有可见引号的命令的确切命令行

因此,我可以很高兴地在bash数组中建立一个命令行,然后用引号将其执行并获得每个引号的引号:

declare -a cmd_args
cmd_args=("-p" "dir path/with spaces")
mkdir "${cmd_args[@]}"
echo dir*/*
Run Code Online (Sandbox Code Playgroud)

但是,如何以一种有意义的方式将其回显到屏幕上,即向用户显示他们可以键入的命令,或者可以将其保存在日志文件中以备将来参考?所有这些看起来(基本上)是相同的:

echo runnimg mkdir with arguments ${cmd_args[@]}
echo runnimg mkdir with arguments "${cmd_args[@]}"
echo "runnimg mkdir with arguments '${cmd_args[@]}'"
echo "runnimg mkdir with arguments '${cmd_args[*]}'"

==> runnimg mkdir with arguments '-p dir path/with spaces'
Run Code Online (Sandbox Code Playgroud)

这显然是错误的命令。这并没有向用户显示他们可以键入的命令,或者我可以保留在日志文件中并在将来的日期重现的命令。我想看看:

runnimg mkdir with arguments '"-p" "dir path/with spaces"'
Run Code Online (Sandbox Code Playgroud)

我考虑过使用cat<<EOF

cat<<EOF 
"${cmd_args[@]}" 
EOF
Run Code Online (Sandbox Code Playgroud)

但实际上,这会在整个参数列表中产生一个很大的报价!这里有什么?这怎么可能永远是我的意图是什么?如果是这样,那我就有"${cmd_args[*]}"

这就是挑战。以用户可以说“是的,这是正确的命令”的方式打印命令。

对那些说“%p \ n”的人表示抱歉,但是对于日志文件来说这可能没问题,但是返回并对其进行“毫不含糊地”格式化以重新测试该命令仍然很麻烦,但它确实不够好交互式“这是命令反馈给用户”。

也许已经有一个答案,但是如果是这样,那么所有“总是引用您的论据”类型的答案就会淹没它。

bash quoting

2
推荐指数
1
解决办法
78
查看次数

标签 统计

c++ ×3

c ×2

c++11 ×2

linux ×2

bash ×1

c++20 ×1

elf ×1

fork ×1

gcc ×1

memory-segmentation ×1

quoting ×1

thread-local-storage ×1

vfork ×1

x86-64 ×1