大家好。
所以我正在学习汇编。
按照我通常学习的任何新语言的学习步骤,我已经到达了使用程序集的网络。
遗憾的是,情况不太好,因为我在第 0 步几乎失败了,这将获得一个可以开始通信的套接字。
汇编代码应大致等于以下 C 代码:
#include <stdio.h>
#include <sys/socket.h>
int main(){
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
}
Run Code Online (Sandbox Code Playgroud)
(让我们忽略它现在没有关闭套接字的事实。)
所以这是我到目前为止所做的:
在某些架构上——例如 x86-64 和 ARM——没有 socketcall() 系统调用;相反,socket(2)、accept(2)、bind(2) 等实际上是作为单独的系统调用实现的。
然而,在系统调用的原始列表中没有这样的调用——据我所知socket(),accept()、bind()、listen()、 等是来自libnet而不是来自内核的调用。这让我很困惑,所以我决定编译上面的C代码并使用strace. 这产生了以下结果:
套接字(PF_INET,SOCK_STREAM,IPPROTO_IP)= 3
虽然这并没有让我更接近于知道它是什么socket() ,但它确实解释了它的论点。对于女巫,我似乎没有找到合适的文档(再次)。我认为PF_INET,SOCK_STREAM,IPPROTO_IP就在被定义<sys/socket.h>,但我grep似乎对他们-ing没有发现使用的东西。所以我决定通过gdb与disass main查找值一起使用来实现它。这给出了以下输出:
汇编代码转储功能主要:0x00000000004004fd …
让我们假设这个结构:
typedef struct mytest_t {
uint8_t field1;
uint32_t field2;
uint64_t field3;
uint64_t field4;
uint16_t field5;
uint32_t field6;
} mytest_t;
Run Code Online (Sandbox Code Playgroud)
还有一些想要创建此结构的函数(有点像一个对象):
int something_with(uint8_t field1, uint32_t field2, uint64_t field3, uint16_t field5) {
mytest_t *object = malloc(sizeof(mytest_t));
object->field1 = field1;
object->field2 = field2;
object->field3 = field3;
object->field4 = 0x12345678;
object->field5 = field5;
object->field6 = 42;
dosomethingwith(object);
return 0;
}
void initial() {
something_with(123, 456, 789, 456);
}
Run Code Online (Sandbox Code Playgroud)
这些功能纯粹是出于我的情况。此函数就像一个帮助程序,在代码中有一个单一的点,在该点上,对象被填充然后转发到其他对象。
注意:这个例子很小,假设参数要长2到3倍。
为了避免将大量参数传递给函数,并使调用变得冗长且难以阅读,我考虑将一个预填充的mytest_t结构作为参数传递(假设需要的字段正确填充)。
将struct作为值或指针传递会更好吗?取消引用所有字段的成本是多少?既然所有内容都在堆栈中,那有什么区别吗?编译器可以某种方式对其进行优化吗?
void initial() {
mytest_t source = {
.field1 = 123, …Run Code Online (Sandbox Code Playgroud) 我正在Linux上学习x86_64程序集,我遇到了一些我希望可以解决的冲突信息.一方面,我已经读过,对于syscall参数,你会按照rdi,rsi,rdx等顺序使用寄存器.但另一方面,我读过你使用寄存器rbx,rcx,rdx等.一个人告诉我,这是因为ABI的原因,但我并不完全明白这究竟意味着什么.
所以我想我要问的是,为什么这两种格式和哪种格式适合使用?
谢谢!
我正在尝试使用sys_brksyscall 在Linux中分配一些内存。这是我尝试过的:
BYTES_TO_ALLOCATE equ 0x08
section .text
global _start
_start:
mov rax, 12
mov rdi, BYTES_TO_ALLOCATE
syscall
mov rax, 60
syscall
Run Code Online (Sandbox Code Playgroud)
事情是按照linux调用约定,我希望返回值在rax寄存器中(指向已分配内存的指针)。我在gdb中运行了此文件,并在进行了sys_brksyscall 后注意到以下寄存器内容
在系统调用之前
rax 0xc 12
rbx 0x0 0
rcx 0x0 0
rdx 0x0 0
rsi 0x0 0
rdi 0x8 8
Run Code Online (Sandbox Code Playgroud)
系统调用后
rax 0x401000 4198400
rbx 0x0 0
rcx 0x40008c 4194444 ; <---- What does this value mean?
rdx 0x0 0
rsi 0x0 0
rdi 0x8 8
Run Code Online (Sandbox Code Playgroud)
rcx在这种情况下,我不太了解寄存器中的值。哪个指针可以用作我分配给它的8个字节的开头的指针sys_brk?
假设我有一个像这样的 nasm 函数:
inc:
mov rax,[rsp + 8]
add [rax],BYTE 1
ret
Run Code Online (Sandbox Code Playgroud)
我这样调用这个函数:
push some_var
call inc
Run Code Online (Sandbox Code Playgroud)
我想通过堆栈将参数传递给函数,因此我压入some_var然后调用我的函数。在函数中,我的项目位于堆栈中的第二个,因此我将其视为:mov rax,[rsp+8]
我的问题是:调用函数后我应该以某种方式从堆栈中弹出我的参数吗?如果是这样,我可以以某种方式从堆栈中删除它,我的意思是弹出它,但不注册?(因为我不再需要这个论点了。)
更新:我发现我可以简单地add rsp,8从堆栈中删除项目。但这是好的做法吗?调用函数后从堆栈中删除参数?
我调用 Clang 12.0.0 来-Os -march=haswell编译以下 C 程序:
int bar(int);
int foo(int x) {
const int b = bar(x);
if (x || b) {
return 123;
}
return 456;
}
Run Code Online (Sandbox Code Playgroud)
生成以下程序集:
foo: # @foo
push rbx
mov ebx, edi
call bar
or eax, ebx
mov ecx, 456
mov eax, 123
cmove eax, ecx
pop rbx
ret
Run Code Online (Sandbox Code Playgroud)
https://gcc.godbolt.org/z/WsGoM56Ez
据我了解,foo 的调用者在 RAX/EAX 中设置了 x。然后 foo 调用 bar,这不需要修改 RAX/EAX,因为 x 是作为未修改的输入传递的。
该or eax, ebx指令似乎是将输入 x 与 bar 的结果进行比较。该结果如何最终进入 EBX?有何目的mov …
我似乎找不到关于 Linux 系统上 NASM x86 中断的好参考。例如,它是什么int 0x60以及它与什么不同int 0x80?
是否有手册列出了可以与int指令结合使用的所有中断号?
我编写了一个程序,它应该像for循环一样,打印一串文本一定次数.
这是代码:
global _start
section .data
msg db "Hello World!",10 ; define the message
msgl equ $ - msg ; define message length
; use minimal size of storage space
imax dd 0x00001000 ; defines imax to be big!
section .text
_start:
mov r8, 0x10 ; <s> put imax in r8d, this will be our 'i' </s>
; just attempt 10 iterations
_loop_entry: ; loop entry point
mov eax, 4 ; setup the message to print
mov ebx, …Run Code Online (Sandbox Code Playgroud) 首先,如果有人知道标准 C 库的一个函数,该函数无需查找二进制零即可打印字符串,但需要绘制字符数,请告诉我!
否则,我有这个问题:
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;
}
Run Code Online (Sandbox Code Playgroud)
GCC 将以下错误告知“int”指令:
"Error: operand size mismatch for 'int'"
Run Code Online (Sandbox Code Playgroud)
有人可以告诉我这个问题吗?
我开始在 ubuntu linux 上使用 NASM 汇编器学习 x86_64 汇编编程。我遇到的问题之一是弄清楚操作神奇地使用了哪些寄存器。
我正在阅读的书有这样的代码示例:
mov rdi, fmt1
mov rsi, strng
mov rax, 0
call printf
; How am I supposed to know which registers are used by the call to printf?
; The libc printf function supports an arbitrary number of parameters.
; Clearly there aren't an unlimited number of registers in x86_64 so how does this work
; as the parameter list grows?
Run Code Online (Sandbox Code Playgroud)
代码示例的另一部分是这样的:
xor rax, rax
mov rbx, strng
mov rcx, strLen
mov …Run Code Online (Sandbox Code Playgroud)