我们以将 16 位有符号数符号扩展为 32 位寄存器为例,例如mov $+/-5, %ax movswl %ax, %ebx。
有两种可能的情况:
高位为零(数字为正)。这是非常容易理解和直观的。例如,如果我有数字5,则用零填充左侧很容易理解。例如:
00000000 00000101 # 5 (represented in 16 bits)
00000000 00000000 00000000 00000101 # 5 (represented in 32 bits)
Run Code Online (Sandbox Code Playgroud)
然而,对我来说最难理解的是当它是负数并且我们进行符号扩展时。例子:
11111111 11111011 # -5 (represented in 16 bits)
11111111 11111111 11111111 11111011 # -5 (represented in 32 bits)
Run Code Online (Sandbox Code Playgroud)
是的,我知道我们只是用 填充高位1。但是什么让它发挥作用呢?也许对二进制数的“属性”的解释可以帮助我更好地理解这一点。
binary assembly bit-manipulation twos-complement sign-extension
我有一个字典列表来模拟解释器的一堆环境。例如,在第一个环境中我可能a=4定义了值,而在第二个环境中我可能已经b=3定义了,所以如果我这样做,env_get(a) + env_get(b)我应该得到7.
这是我目前所拥有的:
def env_get(self, k, env=None):
v = None
for env in reversed(self.envs): # as the "pop" is the equivalent of env[-1]
v = env.get(k)
if v: break
if not v: raise AttributeError("Env does not contain '%s'" % k)
return v
Run Code Online (Sandbox Code Playgroud)
我想知道是否可以将其压缩为单个递归 def ,如下所示:
envs=[{'a':4},{'b':3}]
def get_env_recursive(k, env_stack=None):
if not env_stack: raise AttributeError("Env does not contain '%s'" % k)
return env_stack[-1].get(k) or get_env_recursive(k, env_stack[:-1])
Run Code Online (Sandbox Code Playgroud)
>>> get_env_recursive('a',envs)+get_env_recursive('b',envs)
7
Run Code Online (Sandbox Code Playgroud)
或者对单线发疯可以这样做:
>>> getr=lambda …Run Code Online (Sandbox Code Playgroud) 我理解在函数的开头和结尾使用push rbp...pop rbp来保留rbp调用函数的值,因为rbp寄存器是被调用者保留的。然后我理解使用rbp作为当前正在执行的过程的堆栈帧的当前顶部的“约定” 。但与此相关,我有两个问题:
rbp只是一个约定?我可以像r11堆栈帧的基础一样轻松地使用(或任何其他寄存器甚至堆栈上的 8 个字节)吗?rbp寄存器有什么特别之处,或者它只是用作基于历史和约定的堆栈框架?mov %rbp, %rsp在离开函数之前用作“清理”方法?例如,push/pop指令通常是对称的,所以mov %rbp, %rsp只是一种速记方式,有人可以“跳过”执行对称的弹出/添加等操作?什么mov %rbp, %rsp是有用的实际用途?几乎所有时候我在编译器输出中看到它(启用零优化),它似乎是不必要的或多余的,而且我很难想到它实际上可能有用的场景。在下面,我尝试log在 C 中创建一个实用程序:
#include <stdio.h>
#include <string.h>
enum LogLevel {DEBUG=10, INFO=20, WARN=30, ERROR=40};
typedef struct logger {
int level;
FILE** handlers; // NULL for sentinel
} Logger;
Logger LOGGER;
char* level_str(int level)
{
switch (level) {
case DEBUG: return "DEBUG";
case INFO: return "INFO";
case WARN: return "WARN";
case ERROR: return "ERROR";
default: return "UNKNOWN";
};
}
void logger(char* msg, int level)
{
// skip if level is too low or no handlers set up
if (level < …Run Code Online (Sandbox Code Playgroud) 我编写了以下内容以将本地时间打印为字符串:
char time_buffer[25];
time_t t = time(&t);
strftime(time_buffer, 25, "%c", localtime(&t));
printf("Formatted time: %s\n", time_buffer);
Run Code Online (Sandbox Code Playgroud)
但是,代码对我来说没有太大意义(即使我已经编写了它)。关于它的几个问题:
time_t t = time(&t)工作?这是设置本地时间的结构吗?它从哪里抢时间?time(&t)和localtime(&t)?为什么两者都需要?我试图理解用 python 代码编写的方案过程:
def callcc(proc):
"Call proc with current continuation; escape only"
ball = RuntimeWarning("Sorry, can't continue this continuation any longer.")
def throw(retval): ball.retval = retval; raise ball
try:
return proc(throw)
except RuntimeWarning as w:
if w is ball: return ball.retval
else: raise w
Run Code Online (Sandbox Code Playgroud)
它来自本教程:http : //norvig.com/lispy2.html。
以上是如何工作的?是什么ball意思,为什么 a proc(edure?) 被称为 athrow作为其参数值?评论“仅转义”是什么意思?
顺便说一句,这是我目前(可能是被误导的)对适用于 python 的延续的理解,这类似于传递一个带产量的函数:
def c(func, *args, **kwargs):
# func must be a coroutine
return func(*args, **kwargs)
def inc(x=0):
while True:
yield …Run Code Online (Sandbox Code Playgroud) 请注意,这个问题在这里已经有类似的答案,我想指出:
然而,这个问题更多地询问它们的返回格式以及它们如何相互关联(我认为上面的问题没有完全涵盖)。
_start和之间有什么区别main?在我看来,像ld用途_start,但gcc用途main为切入点。我注意到的另一个区别是main似乎返回值 in %rax,而_start返回值 in%rbx
以下是我看到的两种方式的示例:
.globl _start
_start:
mov $1, %rax
mov $2, %rbx
int $0x80
Run Code Online (Sandbox Code Playgroud)
并运行它:
$ as script.s -o script.o; ld script.o -o script; ./script; echo $?
# 2
Run Code Online (Sandbox Code Playgroud)
另一种方式:
.globl main
main:
mov $3, %rax
ret
Run Code Online (Sandbox Code Playgroud)
并运行它:
$ gcc script.s -o script; ./script; echo $?
3
Run Code Online (Sandbox Code Playgroud)
这两种方法有什么区别?是否main自动调用_start某处,或者它们如何相互关联?为什么一个返回它们的值,rbx而另一个返回它的值rax …