如何将64位地址移动到寄存器



我试图打开程序集中的文件,将内存位置(地址(的值移动到rdi:

mov r13, [rsi+8*1] ; rsi - where addresses of cmdline parameters are.
mov [file_1], r13
; some calls...
mov rax, 2
mov rdi, [file_1] ; 
xor esi, esi ; automatically zero-extended to rsi
syscall

已解决的问题:我确定了文件的长度,但并没有像一样把查找位置放在文件的开头

mov rax, 8
mov rdi, [rsp+.fd_1]
xor esi, esi
mov edx, edx
syscall

调试:

(gdb) p/x &file_1
$1 = 0x601058
(gdb) x/xg 0x601058
0x601058: 0x00007fffffffe16a
(gdb) x/s 0x7fffffffe16a
0x7fffffffe16a: "abc"

但是它不能正确地移动。我还读到mov32位的源操作数,但我需要将64位从内存移动到寄存器。尝试在YASM中使用movq,但它给出了操作码和操作数组合无效的语法错误。

Syscall 2打开一个文件。

参数为:

rax: syscall #2
rdi: pointer: zero terminated filename
rsi: int: flags
rdx: int: mode

您使用以下代码:

...
mov rax, 2          //syscall_2 = open file
...
syscall

然而,根据文件:

给定文件的路径名,open((返回一个文件描述符,一个小的非负整数,用于后续的系统调用。

所以您只完成了第一部分,希望您能得到一个文件描述符,这样您就可以从文件中读取数据了,您需要将该部分添加到代码中
最后,当您完成后,您需要自己清理并关闭文件

让我帮你完成代码。

//********* get a file_descriptor.
push r15             //save non-volatile registers
push r14
mov eax,2            //syscall_2 = open file
mov rdi,[file_1]     //filename
xor esi,esi          //flags = O_RDONLY
xor edx,edx          //mode = 0, good habits: don't leave parameters undefined. 
syscall              //get me a file descriptor (fd).
test eax,eax         //is the fd positive?
mov edi,eax          //param1=fd
mov eax,1            //set failure code, just in case.
js failure           //no,it's negative,report failure.
//*********** read some data
//Step 2, we have a fd, lets read the data in the file.
mov r15,rax          //save the fd in a non-volatile register for later.
xor eax,eax          //syscall_0 = read data from file
mov rsi,[buffer]     //an array to place the data into
                     //`buffer` is the pointer to the buffer. 
mov edx,[len]        //the max_len of the buffer, must be >= 2.
dec edx              //keep an extra byte to put a zero terminator into.
//put 2 zero's if you're reading unicode_16 data.
syscall              //Read that data.
xor r14,r14          //assume a length of zero in case of failure.
                     //we can't jump to failure, we still need to clean up!
test eax,eax         //do we have a fail?
cmovs rax,r14        //if failure, then set zero length result, else do nothing.
mov [len],eax        //set len to the length of data read.
mov byte ptr [buffer+eax],0  //add a zero byte to terminate the data.
//************ clean up
//we are done, got the data. Let's close the file.
mov r14,rax          //if rax=0 then we had an error, store for later use
mov rdi,r15          //param1 = fd
mov eax,3            //syscall_3: close file
syscall              //close that file.
test eax,eax         //did close go ok?
mov eax,3            //set failure code just in case.
js failure           //negative = failure
//************ report back
//if we get here, all went ok, report success and return.
xor eax,eax          //return 0 for success.
//we still need to check if `read()` failed.   
sub r14,1            //carry = 1 only if r14 = 0 = failure else carry = 0
//sub eax,(0+carry)  //if success then no-op else eax=eax-1
sbc eax,eax          //eax = -1 if we had a failure when reading.
failure:
pop r14              //restore non-volatile registers
pop r15
ret                  //all done

大约64位与32位

我还读到mov有32位源操作数〔…〕

这完全是胡说八道。

X64是一款成熟的64位处理器,它可以做到罐头上所说的
如果使用64位寄存器(任何以R开头(不以db结尾(的寄存器(,则使用该寄存器中的所有64位
指向内存的指针应始终进入64位R寄存器
如果寄存器以E开始(或以d结束(,则它是一个32位寄存器(低32位(
对32位寄存器的任何写操作将重叠的64位寄存器的前32位清零,例如mov eax,1rax设置为1;CCD_ 10将CCD_ 11设置为CCD_

CCD_ 13和CCD_
除了CCD_ 15短两个字节并且因此是优选的之外。

如果从内存中读/写,则除非另有指定,否则操作将遵循寄存器的大小
如果将立即数写入内存,则必须指定大小
您不能将64位立即数写入内存,必须使用两条指令才能做到这一点:mov R64,imm64 + mov [mem],R64

洞穴
对16位或8位寄存器的任何写入操作都不会使相关32/64位寄存器的顶部清零!

结论
如果你想编写汇编,你需要真正从头开始学习汇编
因为你是在Linux中编程的,我建议你买一本Jeff Duntemann的书:Assembly Language Step By Step,for Linux
杰夫是一个传奇,他比这个星球上的任何人都能更好地解释组装。

我确定了文件的长度,但并没有将查找位置放在文件的开头

你读到最后,把文件的位置留在EOF,找到了长度吗?首先不要这样做,使用fstat来查找您打开的文件的长度(如果有(。

如果它是一个常规文件或块设备,它会有一个长度,如果它是管道、套接字或tty(或其他字符设备(,它就不会有长度。但是,如果另一个过程修改了它,在你读完它之前,长度可能会改变

文件位置指向末尾的唯一其他方法是使用标志中的O_APPEND打开。


看看系统调用strace cat infloop.c使用了什么(我已经"注释掉"了,并描述了如果您使用固定大小的静态缓冲区,则不相关的内容;如果您愿意,请执行类似的操作(

open("infloop.c", O_RDONLY)             = 3
fstat(3, {st_mode=S_IFREG|0664, st_size=29, ...}) = 0 # get the size
    # fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
    # mmap(NULL, 139264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff78a7eb000    # allocate a buffer
read(3, "nint main()n{n   while(1);n}n", 131072) = 29
write(1, "nint main()n{n   while(1);n}n", 29) = 29
read(3, "", 131072)                     = 0           # read returning 0 means EOF
    # munmap(0x7ff78a7eb000, 139264)          = 0     # free the buffer
close(3)                                = 0

最新更新