首先,如果有人知道标准C库的功能,那么就会打印出来 一个没有查找二进制零的字符串,但需要绘制的字符数,请告诉我!
否则,我有这个问题:
SQLAlchemy
GCC告诉“int”指令出现以下错误:
void printStringWithLength(char *str_ptr, int n_chars){
asm("mov 4, %rax");//Function number (write)
asm("mov 1, %rbx");//File descriptor (stdout)
asm("mov $str_ptr, %rcx");
asm("mov $n_chars, %rdx");
asm("int 0x80");
return;
}
有人可以告诉我这个问题吗?
答案 0 :(得分:4)
您的代码存在许多问题。让我一步一步地看看它们。
首先,int $0x80
系统调用接口仅适用于32位代码。您不应该在64位代码中使用它,因为它只接受32位参数。在64位代码中,使用syscall
接口。系统调用类似,但有些数字不同。
其次,在AT& T汇编语法中,immediates必须以美元符号为前缀。它是mov $4, %rax
,而不是mov 4, %rax
。后者会尝试将地址4
的内容移至rax
,这显然不是您想要的。
第三,您不能仅仅参考内联汇编中的自动变量名称。如果需要,您必须告诉编译器使用扩展汇编要使用哪些变量。例如,在您的代码中,您可以执行以下操作:
asm("mov $4, %%eax; mov $1, %%edi; mov %0, %%esi; mov %2, %%edx; syscall"
:: "r"(str_ptr), "r"(n_chars) : "rdi", "rsi", "rdx", "rax", "memory");
第四,gcc是一个优化编译器。默认情况下,它假定内联汇编语句仅具有您指定的那些副作用。如果您没有指定任何副作用,gcc会假定它没有任何副作用,并删除asm
语句。要解决这个问题,您可以将语句标记为asm volatile
(不好主意)或使用extended inline assembly指定副作用。当您执行后者时,您应该通过不将数据手动移动到寄存器中来简化代码,而是让编译器执行此操作。例如,您的程序集变为:
asm("syscall" :: "a"(SYS_write), "D"(STDOUT_FILENO), "S"(str_ptr), "d"(n_chars) : "memory");
SYS_WRITE
中的<sys/syscall.h>
和STDOUT_FILENO
中的<stdio.h>
定义了syscall
。我不打算向您解释扩展内联汇编的所有细节。一般使用内联汇编通常是个坏主意。如果您有兴趣,请阅读文档。
第五,尽可能避免使用内联汇编。例如,要进行系统调用,请使用unistd.h
中的syscall(SYS_write, STDOUT_FILENO, str_ptr, (size_t)n_chars);
函数:
write(STDOUT_FILENO, str_ptr, n_chars);
这是正确的。
第六,始终检查您要呼叫的系统呼叫是否已在C标准库中可用。在这种情况下,它是,所以你应该写
stdio
完全避免所有这些。
第七,如果您更喜欢使用fwrite
,请改用fwrite(str_ptr, 1, n_chars, stdout);
:
master
答案 1 :(得分:3)
你的代码有很多问题(并且没有理由使用内联asm),不值得尝试实际修正它们。相反,use the write(2)
system call通常的方式,通过手册页中记录的POSIX函数/ libc包装器,或使用ISO C <stdio.h>
fwrite(3)
。
#include <unistd.h>
static inline
void printStringWithLength(const char *str_ptr, int n_chars){
write(1, str_ptr, n_chars);
// TODO: check error return value
}
为什么您的代码无法汇编:
在AT&amp; T语法中,immediates 总是需要一个$
装饰器。如果您使用asm("int $0x80")
,您的代码将会汇总。
汇编程序抱怨0x80
,它是绝对地址0x80
的内存引用。没有form of int
将中断向量作为立即数以外的任何东西。我不确定为什么它抱怨 size ,因为内存引用在AT&amp; T语法中没有隐含的大小。
这将使它组装,此时你会得到链接器错误:
In function `printStringWithLength':
5 : <source>:5: undefined reference to `str_ptr'
6 : <source>:6: undefined reference to `n_chars'
collect2: error: ld returned 1 exit status
(from the Godbolt compiler explorer)
mov $str_ptr, %rcx
表示将符号str_ptr
的地址立即移动到%rcx
。在AT&amp; T语法中,您不必在使用外部符号之前声明外部符号,因此假定未知名称是全局/静态标签。如果你有一个名为str_ptr
的全局变量,那么该指令将引用它的地址(这是一个链接时间常量,因此可以用作立即数)。
正如其他人所说,这是完全使用GNU C inline asm进行操作的错误方法。有关指南的更多链接,请参阅inline-assembly代码Wiki。
另外,你使用的是错误的ABI。 int $0x80
是x86 32位系统调用ABI,因此它不适用于64位指针。 What are the calling conventions for UNIX & Linux system calls on x86-64
另请参阅x86标记wiki。