小编car*_*ass的帖子

为什么 2 的补码符号扩展通过添加符号位的副本来工作?

我们以将 16 位有符号数符号扩展为 32 位寄存器为例,例如mov $+/-5, %ax movswl %ax, %ebx

有两种可能的情况:

  1. 高位为零(数字为正)。这是非常容易理解和直观的。例如,如果我有数字5,则用零填充左侧很容易理解。例如:

                      00000000 00000101    # 5 (represented in 16 bits)
    00000000 00000000 00000000 00000101    # 5 (represented in 32 bits)
    
    
    Run Code Online (Sandbox Code Playgroud)
  2. 然而,对我来说最难理解的是当它是负数并且我们进行符号扩展时。例子:

                      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

2
推荐指数
1
解决办法
3092
查看次数

递归查找变量

我有一个字典列表来模拟解释器的一堆环境。例如,在第一个环境中我可能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)

python

2
推荐指数
1
解决办法
42
查看次数

为什么 RBP 而不是另一个寄存器作为帧指针?

我理解在函数的开头和结尾使用push rbp...pop rbp来保留rbp调用函数的值,因为rbp寄存器是被调用者保留的。然后我理解使用rbp作为当前正在执行的过程的堆栈帧的当前顶部的“约定” 。但与此相关,我有两个问题:

  1. 是否rbp只是一个约定?我可以像r11堆栈帧的基础一样轻松地使用(或任何其他寄存器甚至堆栈上的 8 个字节)吗?rbp寄存器有什么特别之处,或者它只是用作基于历史和约定的堆栈框架?
  2. 为什么mov %rbp, %rsp在离开函数之前用作“清理”方法?例如,push/pop指令通常是对称的,所以mov %rbp, %rsp只是一种速记方式,有人可以“跳过”执行对称的弹出/添加等操作?什么mov %rbp, %rsp是有用的实际用途?几乎所有时候我在编译器输出中看到它(启用零优化),它似乎是不必要的或多余的,而且我很难想到它实际上可能有用的场景。

x86 assembly pointers x86-64 stack-frame

2
推荐指数
1
解决办法
108
查看次数

在 C 中做一个记录器

在下面,我尝试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)

c

1
推荐指数
1
解决办法
69
查看次数

了解 time_t 调用

我编写了以下内容以将本地时间打印为字符串:

 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)?为什么两者都需要?

c

1
推荐指数
1
解决办法
44
查看次数

理解 call-with-continuation 的实现

我试图理解用 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)

lisp python scheme continuations callcc

1
推荐指数
1
解决办法
127
查看次数

main 与 _start 中的返回值

请注意,这个问题在这里已经有类似的答案,我想指出:

然而,这个问题更多地询问它们的返回格式以及它们如何相互关联(我认为上面的问题没有完全涵盖)。


_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 …

c assembly program-entry-point x86-64

0
推荐指数
1
解决办法
278
查看次数