当我尝试使用LD_PRELOAD时,如下
LD_PRELOAD=getpid.so ./testpid
Run Code Online (Sandbox Code Playgroud)
我收到以下错误...
ERROR: ld.so: object 'getpid.so' from LD_PRELOAD cannot be preloaded: ignored.
Run Code Online (Sandbox Code Playgroud)
我使用编译getpid.so
gcc -Wall -fPIC -shared -o getpid.so getpid.c
Run Code Online (Sandbox Code Playgroud)
它包含以下代码......
// getpid.c
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
pid_t getpid(void)
{
printf("Hello, world!\n");
return syscall(SYS_getpid);
}
Run Code Online (Sandbox Code Playgroud)
tespid.c 使用getpid的constains代码,如下所示,并通过执行编译
gcc testpid -o testpid.c
Run Code Online (Sandbox Code Playgroud)
这可能是什么问题?为什么LD_PRELOAD不起作用?
// testpid.c
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
printf( "pid = %d!\n", getpid() );
return 0;
}
Run Code Online (Sandbox Code Playgroud) 我有兴趣使用x86-64与gcc的SSE向量指令,并且不想为此使用任何内联汇编.有没有办法在C中做到这一点?如果是这样,有人可以举个例子吗?
这可能完全重复 是否可以通过模式切换在64位进程中执行32位代码?,但这个问题是从一年前开始的,只有一个答案没有给出任何源代码.我希望得到更详细的答案.
我正在运行64位Linux(Ubuntu 12.04,如果重要的话).这里有一些代码可以分配页面,将一些64位代码写入其中,然后执行该代码.
#include <assert.h>
#include <malloc.h>
#include <stdio.h>
#include <sys/mman.h> // mprotect
#include <unistd.h> // sysconf
unsigned char test_function[] = { 0xC3 }; // RET
int main()
{
int pagesize = sysconf(_SC_PAGE_SIZE);
unsigned char *buffer = memalign(pagesize, pagesize);
void (*func)() = (void (*)())buffer;
memcpy(buffer, test_function, sizeof test_function);
// func(); // will segfault
mprotect(buffer, pagesize, PROT_EXEC);
func(); // works fine
}
Run Code Online (Sandbox Code Playgroud)
现在,纯粹是为了娱乐价值,我想做同样的事情,但buffer包含任意32位(ia32)代码,而不是64位代码.此页面意味着您可以通过将CS段描述符的位设置为"长兼容性子模式"来在64位处理器上执行32位代码LMA=1, L=0, D=1.我愿意将我的32位代码包装在执行此设置的序言/结尾中.
但我可以在Linux中以usermode进行此设置吗?(BSD/Darwin的答案也将被接受.)这是我开始对这些概念感到朦胧的地方.我认为解决方案涉及向GDT添加新的段描述符(或者是LDT?),然后通过lcall指令切换到该段.但是所有这些都可以在usermode中完成吗?
这是一个示例函数,在兼容性子模式下成功运行时应返回4,在长模式下运行时应返回8.我的目标是获取指令指针以获取此代码路径并从另一端出来%rax=4,而不会进入内核模式(或仅通过记录的系统调用执行此操作). …
我在一篇博客文章中读到,最近的X86微体系结构也能够在寄存器重命名器中处理常见的寄存器归零习语(例如将寄存器与自身对齐); 用作者的话来说:
"寄存器重命名器也知道如何执行这些指令 - 它可以将寄存器本身归零."
有人知道这在实践中是如何运作的吗?我知道有些ISA,如MIPS,包含一个在硬件中始终设置为零的架构寄存器; 这是否意味着在内部,X86微体系结构内部具有类似的"零"寄存器,以便在方便时映射到寄存器?或者我的心智模型对于这些东西如何在微体系结构上工作不太正确?
我之所以要问的原因是(从一些观察中)看来mov,在一个循环中,从一个包含零的寄存器到一个目的地,仍然比在循环内通过xor将寄存器归零要快得多.
基本上它发生的是我想根据条件将循环内的寄存器归零; 这可以通过提前分配架构寄存器来存储零(%xmm3在这种情况下),在整个循环期间不进行修改,并在其中执行以下内容来完成:
Run Code Online (Sandbox Code Playgroud)movapd %xmm3, %xmm0
或者用xor技巧代替:
Run Code Online (Sandbox Code Playgroud)xorpd %xmm0, %xmm0
(AT&T语法).
换句话说,选择是在循环之外提升常数零或在每次迭代中将其重新物化在其中.后者将实时架构寄存器的数量减少一个,并且通过处理器假设的特殊情况感知和处理xor成语,它似乎应该像前者一样快(特别是因为这些机器具有更多的物理无论如何,寄存器都比体系结构寄存器更重要,所以它应该能够在内部完成与我在程序集中所做的相同的工作,通过在内部提升常数零甚至更好,完全意识和控制自己的资源).但它似乎不是,所以我很好奇是否有任何具有CPU架构知识的人可以解释是否有一个很好的理论原因.
在这种情况下,寄存器由SSE寄存器发生,机器恰好是Ivy Bridge; 我不确定这些因素有多重要.
当我打破主要时,它看起来像粗线是我正在创建和初始化的地方.我想我错了,我正试图从一本解释x86的书中检查x86_64程序集.这看起来很奇怪,我很确定我只是不明白,因为在本书中他说他会将单词和双字称为4字节.如果我能得到一个解释来帮助我的认知,我将不胜感激.
__CODE__方法:http://ruby-doc.org/core-2.0.0/Enumerable.html#method-i-inject
我正在阅读syscall的以下定义:
.text
.globl syscall
.type syscall,%function
.align 16
syscall:
movq %rdi, %rax /* Syscall number -> rax. */
movq %rsi, %rdi /* shift arg1 - arg5. */
movq %rdx, %rsi
movq %rcx, %rdx
movq %r8, %r10
movq %r9, %r8
movq 8(%rsp),%r9 /* arg6 is on the stack. */
syscall /* Do the system call. */
cmpq $-4095, %rax /* Check %rax for error. */
jae __syscall_error /* Branch forward if it failed. */
ret /* Return to caller. */
.size …Run Code Online (Sandbox Code Playgroud) 所述X86-64 ABI指定两个返回寄存器:rax和rdx,在大小两个64位(8个字节).
假设x86-64是唯一的目标平台,这两个功能中的哪一个:
uint64_t f(uint64_t * const secondReturnValue) {
/* Calculate a and b. */
*secondReturnValue = b;
return a;
}
std::pair<uint64_t, uint64_t> g() {
/* Calculate a and b, same as in f() above. */
return { a, b };
}
Run Code Online (Sandbox Code Playgroud)
考虑到针对x86-64的C/C++编译器的当前状态,会产生更好的性能吗?使用一个版本或其他版本是否存在性能方面的任何陷阱?编译器(GCC,Clang)总是能够优化std::pair返回rax和rdx吗?
更新:通常,如果编译器优化std::pair方法(使用GCC 5.3.0和Clang 3.8.0的二进制输出示例),则返回一对更快.如果f()没有内联,编译器必须生成代码以将值写入内存,例如:
movq b, (%rdi)
movq a, %rax
retq
Run Code Online (Sandbox Code Playgroud)
但是如果g()编译器满足要求:
movq a, %rax …Run Code Online (Sandbox Code Playgroud) 在尝试优化x86_64上的返回值时,我注意到一件奇怪的事情.即,给出代码:
#include <cstdint>
#include <tuple>
#include <utility>
using namespace std;
constexpr uint64_t a = 1u;
constexpr uint64_t b = 2u;
pair<uint64_t, uint64_t> f() { return {a, b}; }
tuple<uint64_t, uint64_t> g() { return tuple<uint64_t, uint64_t>{a, b}; }
Run Code Online (Sandbox Code Playgroud)
Clang 3.8输出此汇编代码f:
movl $1, %eax
movl $2, %edx
retq
Run Code Online (Sandbox Code Playgroud)
这个用于g:
movl $2, %eax
movl $1, %edx
retq
Run Code Online (Sandbox Code Playgroud)
哪个看起来最佳.但是,使用GCC 6.1编译时,生成的程序集f与Clang输出相同,生成的程序集为g:
movq %rdi, %rax
movq $2, (%rdi)
movq $1, 8(%rdi)
ret
Run Code Online (Sandbox Code Playgroud)
看起来返回值的类型被GCC归类为MEMORY,而Clang归类为INTEGER.我可以确认将Clang代码与GCC代码链接这样的代码可能会导致分段错误(Clang调用GCC编译 …
看看这段代码:
one.cpp:
bool test(int a, int b, int c, int d);
int main() {
volatile int va = 1;
volatile int vb = 2;
volatile int vc = 3;
volatile int vd = 4;
int a = va;
int b = vb;
int c = vc;
int d = vd;
int s = 0;
__asm__("nop"); __asm__("nop"); __asm__("nop"); __asm__("nop");
__asm__("nop"); __asm__("nop"); __asm__("nop"); __asm__("nop");
__asm__("nop"); __asm__("nop"); __asm__("nop"); __asm__("nop");
__asm__("nop"); __asm__("nop"); __asm__("nop"); __asm__("nop");
for (int i=0; i<2000000000; i++) {
s += test(a, b, …Run Code Online (Sandbox Code Playgroud) 我想获得在c中添加两个无符号64位整数的进位位。如果需要,我可以使用x86-64 asm。码:
#include <stdio.h>
typedef unsigned long long llu;
int main(void){
llu a = -1, b = -1;
int carry = /*carry of a+b*/;
llu res = a+b;
printf("a+b = %llu (because addition overflowed), carry bit = %d\n", res, carry);
return 0;
}
Run Code Online (Sandbox Code Playgroud)