- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我刚刚编写了一个 C 程序,它在不使用标准库或 main()
函数的情况下打印其命令行参数。我的动机只是好奇心和了解如何玩内联汇编。我将 Ubuntu 17.10 x86_64 与 4.13.0-39 通用内核和 GCC 7.2.0 一起使用。
下面是我的代码,我已经尽可能多地评论了我的理解。系统需要函数 print
、 print_1
、 my_exit
和 _start()
来运行可执行文件。实际上,如果没有 _start()
,链接器将发出警告并且程序将出现段错误。
函数 print
和 print_1
是不同的。第一个向控制台打印出一个字符串,在内部测量字符串的长度。第二个函数需要将字符串长度作为参数传递。 my_exit()
函数只是退出程序,返回所需的值,在我的例子中是字符串长度或命令行参数的数量。print_1
需要字符串长度作为参数,因此使用 while()
循环对字符进行计数,并将长度存储在 strLength
中。在这种情况下,一切正常。
当我使用 print
函数时会发生奇怪的事情,该函数在内部测量字符串长度。简单地说,这个函数似乎以某种方式将字符串指针更改为指向环境变量,该变量应该是下一个指针,而不是第一个参数,该函数打印 "CLUTTER_IM_MODULE=xim"
,这是我的第一个环境变量。我的解决方法是在下一行中将 *a
分配给 *b
。
我在计数过程中找不到任何解释,但看起来它正在改变我的字符串指针。
unsigned long long print(char * str){
unsigned long long ret;
__asm__(
"pushq %%rbx \n\t"
"pushq %%rcx \n\t" //RBX and RCX to the stack for further restoration
"movq %1, %%rdi \n\t" //pointer to string (char * str) into RDI for SCASB instruction
"movq %%rdi, %%rbx \n\t" //saving RDI in RBX for final substraction
"xor %%al, %%al \n\t" //zeroing AL for SCASB comparing
"movq $0xffffffff, %%rcx \n\t" //max string length for REPNE instruction
"repne scasb \n\t" //counting "loop" see details: https://www.felixcloutier.com/x86/index.html for REPNE and SCASB instructions
"sub %%rbx, %%rdi \n\t" //final substraction
"movq %%rdi, %%rdx \n\t" //string length for write syscall
"movq %%rdi, %0 \n\t" //string length into ret to return from print
"popq %%rcx \n\t"
"popq %%rbx \n\t" //RBX and RCX restoration
"movq $1, %%rax \n\t" //write - 1 for syscall
"movq $1, %%rdi \n\t" //destination pointer for string operations $1 - stdout
"movq %1, %%rsi \n\t" //source string pointer
"syscall \n\t"
: "=g"(ret)
: "g"(str)
);
return ret; }
void print_1(char * str, int l){
int ret = 0;
__asm__("movq $1, %%rax \n\t" //write - 1 for syscall
"movq $1, %%rdi \n\t" //destination pointer for string operations
"movq %1, %%rsi \n\t" //source pointer for string operations
"movl %2, %%edx \n\t" //string length
"syscall"
: "=g"(ret)
: "g"(str), "g" (l));}
void my_exit(unsigned long long ex){
int ret = 0;
__asm__("movq $60, %%rax\n\t" //syscall 60 - exit
"movq %1, %%rdi\n\t" //return value
"syscall\n\t"
"ret"
: "=g"(ret)
: "g"(ex)
);}
void _start(){
register int ac __asm__("%rsi"); // in absence of main() argc seems to be placed in rsi register
//int acp = ac;
unsigned long long strLength;
if(ac > 1){
register unsigned long long * arg __asm__("%rsp"); //argv array
char * a = (void*)*(arg + 7); //pointer to argv[1]
char * b = a; //work around for print function
/*version with print_1 and while() loop for counting
unsigned long long strLength = 0;
while(*(a + strLength)) strLength++;
print_1(a, strLength);
print_1("\n", 1);
*/
strLength = print(b);
print("\n");
}
//my_exit(acp); //echo $? prints argc
my_exit(strLength); //echo $? prints string length}
最佳答案
char * a = (void*)*(arg + 7);
完全是一个“碰巧工作”的东西,如果它真的有效的话。除非您正在编写仅使用内联 asm 的 __attribute__((naked))
函数,否则完全取决于编译器如何布置堆栈内存。看起来您正在获取 rsp
,尽管对于这种不受支持的 register-asm 本地使用并不能保证。 (仅当用作内联 asm 语句的操作数时才能保证使用请求的寄存器。)
如果您在禁用优化的情况下编译,gcc 将为本地人保留堆栈槽,因此 char * b = a;
使 gcc 在函数入口 上通过更多调整 RSP,这就是为什么您的 hack 碰巧更改了 gcc 的代码生成以匹配硬编码的 +7
(8 次)字节)偏移量放在源中。
在进入 _start
时,堆栈内容是: argc
处的 (%rsp)
, argv[]
开始于 8(%rsp)
。在 argv[] 的终止 NULL 指针上方,envp[]
数组也在堆栈内存中。所以这就是为什么当你的硬编码偏移量获得错误的堆栈槽时你会得到 CLUTTER_IM_MODULE=xim
的原因。
// in absence of main() argc seems to be placed in rsi register
_start
之前在您的进程中运行)遗留下来的。如果您使用
gcc -static -nostdlib -fno-pie
编译,您的
_start
将是直接从内核到达的真正进程入口点,所有寄存器 = 0(RSP 除外)。请注意,ABI 表示未定义; Linux 选择将它们归零以避免信息泄漏。
void _start(){}
,无论是否启用优化都可以可靠地工作,并且出于正确的原因工作,没有内联 asm (但仍然依赖于 x86-64 SysV ABI 的调用约定和进程入口堆栈布局) .不需要对 gcc 的代码生成中碰巧发生的偏移进行硬编码。
How Get arguments value using inline assembly in C without Glibc? 。它使用
int argc = (int)__builtin_return_address(0);
之类的东西,因为
_start
不是函数:堆栈上的第一件事是 argc 而不是返回地址。它不漂亮也不推荐,但考虑到调用约定,这就是如何让 gcc 生成知道事物在哪里的代码。
"syscall"
,就像这个很好的示例
my_write
函数:
How to invoke a system call via sysenter in inline assembly?(实际答案有 32 位
int $0x80
和 x86 -64
syscall
,但不是使用 32 位
sysenter
的内联 asm 版本,因为这不是保证稳定的 ABI)。
"memory"
clobber,或查看
at&t asm inline c++ problem 以了解虚拟操作数解决方法。
关于C - 打印没有标准库的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51127399/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!