我想检查放入---
title: "RMD_Example"
output: html_document
---
```{r setup, include=FALSE}
# Load ggplot2
library(ggplot2)
# Define helper function
adjust_title_position <- function(p) {
# Shift the horizontal position of the plot title
p_built <- invisible(ggplot2::ggplot_build(p))
gt <- invisible(ggplot2::ggplot_gtable(p_built))
gt$layout[which(gt$layout$name == "title"), c("l", "r")] <- c(2, max(gt$layout$r))
# Prints the plot to the current graphical device
gridExtra::grid.arrange(gt, newpage = TRUE)
# Invisibly return the gtable object
invisible(gt)
}
```
```{r plot_1}
ggplot(mtcars) + geom_point(aes(x = wt, y = mpg)) +
labs(title = "Weights and miles-per-gallon")
```
```{r plot_2}
ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width)) + geom_point() +
labs(title = "Sepal length and width")
```
寄存器中的值I
是负的还是空的8字节值(在C语言中为负的rax
)。
它导致我检查long int
寄存器中的64位是否与带符号的位值相对应。
经过研究,我发现如果我们将base10中的-86之类的值的每个位取反并加1,我们将获得取反值86。
基于此,在位方面,负的反转值将小于负值。
我正在 x86_64 Linux 上的 NASM 中构建和运行代码。
我正在应用以下代码,当rax
为负数时显示一条消息:
I
这是我编译 NASM 代码的方式:
section .data
msg db "I is negative", 0
section .text
global main
extern printf, exit
%define I 9
main:
mov rax, I
; Invert the bits into rax
xor rax, 0xFFFFFF
inc rax
mov rbx, I
cmp rax, rbx
jl EXIT
; Display message when I is negative
lea rdi, [msg]
xor rax, rax
call printf
EXIT:
call exit
ret
但是该程序是错误的,因为它无法正常工作。
似乎我误解了检查寄存器是否包含负整数的方式。有帮助吗?
答案 0 :(得分:3)
比这容易得多。对64位执行test rax, rax
,对于32位执行test eax, eax
。
然后使用条件指令检查标志标志(SF)。如果已设置,则该数字为负。
答案 1 :(得分:3)
EAX是RAX的低4字节。
test eax,eax ; sets flags the same as cmp eax,0, like from eax-0
jnl I_was_non_negative ; jumps if EAX was *not* less-than 0. Synonym for jge
Test whether a register is zero with CMP reg,0 vs OR reg,reg?解释了为什么test
的效率要比cmp
略高一些,以与零比较。 (通常是代码大小的1个字节)。
l
小于条件测试SF和OF,但是与零进行比较不会溢出,因此,这等效于仅测试SF(从结果的MSB设置的符号标志)。在这种情况下,您可以选择jnl
或jns
(不少于或未签名)或jge
。选择任何一个您最喜欢的语义。
int
是4个字节,而不是8个。 (在所有标准的32位和64位x86 ABI中,包括在Linux上可以找到的x86-64 System V)。
您尝试使用2的补码身份实现-I < I
(我认为)时遇到的问题
-x = ~x + 1
xor rax, 0xFFFFFF
仅翻转低24位(即6 F
位,而不是8位)。
但是xor rax, 0xFFFFFFFF
不可编码,因为它不适合32位符号扩展的立即数。即使对于64位操作数大小,x86-64仍然使用8或32位立即数,而不是8或64,因为这将是非常膨胀的代码大小。有关可编码的内容,请参见https://felixcloutier.com/x86/XOR.html。 (有一个mov r64, imm64
,但这是唯一需要64位立即数的指令。)
因此,如果您使用xor eax, -1
(或not eax
)而不是坚持使用64位操作数大小,则可能您的怪异代码会比较-I < I
。但是翻转64位寄存器的低32位或24位,然后进行64位比较是没有帮助的。高位将始终为零。
如果您使用的是32位比较,那么对于负数最大的数字可能会遇到问题。 0x80000000
是它自己的2的补码逆。即neg eax
会保持不变(并设置OF,因为0 - 0x80000000
导致有符号的溢出恢复为负)。
如果您在否定之前将EAX中的4字节输入符号扩展为RAX中的8字节,那么它可以正常工作。
mov eax, I
movsxd rax, eax ; or cdqe
; not rax
; inc rax
neg rax
cmp rax, I ; use I as a sign-extended 32-bit immediate
jl I_is_positive ; won't be taken for 0 either.
请注意正负之间的区别。 -I < I
在I = 0时为假,但您询问是否要检查是否为负(非负的相反,而不是正的相反)。
I
是一个汇编时间常量您可以使用the NASM preprocessor对其进行测试。
default rel ; always a good idea to use RIP-relative for static data
; %define I 9
extern puts
global main
main:
%if I < 0
lea rdi, [rel msg]
xor eax, eax
call puts ; puts appends a newline
%endif
xor eax,eax ; return 0. Otherwise we might as well jmp puts to tailcall it
ret
section .rodata ; read-only data can go here
msg: db "I is negative", 0 ; colon after labels is always good style in NASM
我注释掉了%define
,因此可以在命令行中通过它:
$ nasm -felf64 -DI=0 nasm.asm && gcc -no-pie nasm.o && ./a.out # no output for I=0
$ nasm -felf64 -DI=9 nasm.asm && gcc -no-pie nasm.o && ./a.out # or I=9
$ nasm -felf64 -DI=-9 nasm.asm && gcc -no-pie nasm.o && ./a.out
I is negative
$ nasm -felf64 -DI=0x80000000 nasm.asm && gcc -no-pie nasm.o && ./a.out # NASM doesn't truncate to 32-bit 2's complement though.
$ nasm -felf64 -DI=0x8000000000000000 nasm.asm && gcc -no-pie nasm.o && ./a.out # apparently it's 64-bit.
我必须使用-no-pie
,因为我使用了call puts
而不是call puts@plt
或任何与PIE兼容的东西。由于某些原因,链接器在编写PIE而不是位置相关的可执行文件时,不会重写直接调用以使用PLT。