0%

源文件

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>

int add(int x,int y) {
return x + y;
}

int main(int argc,char** arg) {

printf("%d + %d = %d",1,2,add(1,2));
return 0;
}

汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
	.section	__TEXT,__text,regular,pure_instructions
.build_version macos, 13, 0 sdk_version 13, 3
.globl _add ## -- Begin function add
.p2align 4, 0x90
_add: ## @add
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
movl -4(%rbp), %eax
addl -8(%rbp), %eax
popq %rbp
retq
.cfi_endproc
## -- End function
.globl _main ## -- Begin function main
.p2align 4, 0x90
_main: ## @main
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
subq $16, %rsp
movl $0, -4(%rbp)
movl %edi, -8(%rbp)
movq %rsi, -16(%rbp)
movl $1, %edi
movl $2, %esi
callq _add
movl %eax, %ecx
leaq L_.str(%rip), %rdi
movl $1, %esi
movl $2, %edx
movb $0, %al
callq _printf
xorl %eax, %eax
addq $16, %rsp
popq %rbp
retq
.cfi_endproc
## -- End function
.section __TEXT,__cstring,cstring_literals
L_.str: ## @.str
.asciz "%d + %d = %d"

.subsections_via_symbols

逐行代码解析

  1. .section __TEXT,__text,regular,pure_instructions: 定义一个新的段(section),名为__TEXT,__text,用于存放正文(代码);regularpure_instructions是段的属性,表示该段包含普通的指令集和纯指令(无数据)。

  2. .build_version macos, 13, 0 sdk_version 13, 3: 声明编译的版本信息,表示此程序的目标操作系统版本为 macOS 13.0,使用的 SDK 版本为 13.3。

  3. .globl _add: 声明全局符号 _add,用于表示函数add的入口。

  4. .p2align 4, 0x90: 确保下一个指令的地址在16字节对齐位置上。

  5. _add:: 函数add的标签,表示函数的入口。

  6. .cfi_startproc: 声明函数的开始,用于生成调试信息。

  7. pushq %rbp: 将寄存器%rbp的值压入栈中,保存之前的栈帧指针。

  8. .cfi_def_cfa_offset 16: 定义栈帧指针偏移,将栈帧大小设置为16字节。

  9. .cfi_offset %rbp, -16: 定义寄存器%rbp的位置在栈的偏移量为-16。

  10. movq %rsp, %rbp: 将当前栈指针%rsp的值赋给栈帧指针%rbp,建立新的栈帧。

  11. .cfi_def_cfa_register %rbp: 定义新的栈帧指针寄存器为%rbp

  12. movl %edi, -4(%rbp): 将函数的第一个参数(整型)移动到栈帧中的位置,偏移量为-4。

  13. movl %esi, -8(%rbp): 将函数的第二个参数(整型)移动到栈帧中的位置,偏移量为-8。

  14. movl -4(%rbp), %eax: 将栈帧中的第一个参数加载到通用寄存器%eax中。

  15. addl -8(%rbp), %eax: 将栈帧中的第二个参数与%eax寄存器的值相加。

  16. popq %rbp: 弹出保存的栈帧指针。

  17. retq: 返回函数,将栈帧指针弹出到程序计数器,并跳转到调用函数的位置。

  18. .cfi_endproc: 声明函数的结束,停止生成调试信息。

  19. .globl _main: 声明全局符号 _main,用于表示函数main的入口。

  20. .p2align 4, 0x90: 确保下一个指令的地址在16字节对齐位置上。

  21. _main:: 函数main的标签,表示函数的入口。

  22. .cfi_startproc: 声明函数的开始,用于生成调试信息。

  23. pushq %rbp: 将寄存器%rbp的值压入栈中,保存之前的栈帧指针。

  24. .cfi_def_cfa_offset 16: 定义栈帧指针偏移,将栈帧大小设置为16字节。

  25. .cfi_offset %rbp, -16: 定义寄存器%rbp的位置在栈的偏移量为-16。

  26. movq %rsp, %rbp: 将当前栈指针%rsp的值赋给栈帧指针%rbp,建立新的栈帧。

  27. .cfi_def_cfa_register %rbp: 定义新的栈帧指针寄存器为%rbp

  28. subq $16, %rsp: 在栈上分配16字节的空间,为本地变量的使用而预留。

  29. movl $0, -4(%rbp): 初始化栈帧中的一个本地变量,将值0存储在偏移量为-4的位置。

  30. movl %edi, -8(%rbp): 将函数的第一个参数(整型)移动到栈帧中的位置,偏移量为-8。

  31. movq %rsi, -16(%rbp): 将函数的第二个参数(整型)移动到栈帧中的位置,偏移量为-16。

  32. movl $1, %edi: 将值1存储在寄存器%edi中,准备作为第一个参数传递给_add函数。

  33. movl $2, %esi: 将值2存储在寄存器%esi中,准备作为第二个参数传递给_add函数。

  34. callq _add: 调用函数_add,将参数传递给它,并开始执行该函数。

  35. movl %eax, %ecx: 将_add函数的返回值(存储在寄存器%eax中)移动到寄存器%ecx中,准备作为参数传递给printf函数。

  36. leaq L_.str(%rip), %rdi: 将字符串L_.str的地址(存储在相对寻址中)加载到寄存器%rdi中,作为printf函数的第一个参数。

  37. movl $1, %esi: 将值1存储在寄存器%esi中,准备作为printf函数的第二个参数。

  38. movl $2, %edx: 将值2存储在寄存器%edx中,准备作为printf函数的第三个参数。

  39. movb $0, %al: 将值0存储在寄存器%al中,准备作为printf函数的第四个参数。

  40. callq _printf: 调用printf函数,将之前准备好的参数传递给它,开始执行打印操作。

  41. xorl %eax, %eax: 将寄存器%eax与自身进行异或操作,将结果存储回%eax,相当于将其清零。

  42. addq $16, %rsp: 释放之前预留的16字节的栈空间。

  43. popq %rbp: 弹出保存的栈帧指针。

  44. retq: 返回函数,将栈帧指针弹出到程序计数器,并跳转到程序的结束点。

  45. .cfi_endproc: 声明函数的结束,停止生成调试信息。

  46. .section __TEXT,__cstring,cstring_literals: 定义一个新的段(section),名为__TEXT,__cstring,用于存放c字符串字面量。

  47. L_.str: .asciz "%d + %d = %d": 定义一个c字符串字面量"%d + %d = %d",并使用标签L_.str进行引用。

  48. .subsections_via_symbols: 告诉编译器按照符号(symbol)来生成子段(subsections)。

以上就是汇编代码的逐行解释,希望能帮助你理解代码的功能和执行流程。

前言

以下所有内容来自我对<<CSS世界>>的摘录和总结,感谢原作者辛苦著书。

1. 拥抱流布局

  1. 布局(layout)
    1. 响应式与媒体查询
    2. flexible box layout
    3. grid layout
  2. 视觉表现
    1. corner、shadow、progressive
    2. transform
    3. fitler
    4. animatation

2. 术语

1
2
3
4
5
.track-item {
width: 480px;
height : 640px;
color : 'red';
}
  1. 属性
    heightcolor就是属性。
类型 说明
int 属于number
number 浮点数
percent 50%
length 99px
color #999
  1. 关键字
    transparent

  2. 变量
    currentColor

  3. 长度单位

<number> + 长度单位 = <length>

  1. 功能符
    rgba(0,0,0,5)
    url('css-world.png')

  2. 属性值
    1px solid rgb(0,0,0) <- 值+关键字+功能符

  3. 声明
    color : transparent

  4. 声明块

    1
    2
    3
    4
    {
    width : 10%,
    color : 'red'
    }
  5. 规则或规则集

    1
    2
    3
    4
    5
    .track-item {
    width: 480px;
    height : 640px;
    color : 'red';
    }
  6. 选择器

选择器 符号 优先级
类选择器 ‘.’ 默认
ID选择器 ‘#’
属性选择器 ‘[]’
伪类选择器 ‘:’
伪元素选择器 ‘::before’

3. 布局–从block开始

3.1 block-level element

元素 display
<div> block
<li> list-item
<table> block

一个水平流上只能单独显示一个元素,多个块级元素则换行显示。
正是由于块级元素具有换行特性,因此理论上它都可以配合clear属性
来清除浮动带来的影响。

简化layout解释

a. 不考虑list-item的情况下
| 盒子 | 职责 |
| - | - |
| block-level box | 结构 |
| inline box | 内容 |

b. 考虑list-item当前情况下

盒子 职责
block-level box 主块级盒子
inline box 内容
list-item 附加盒子

c. inline-block加入战场

盒子 职责
block-level box 主块级盒子
inline box 内容
list-item 附加盒子
inline-block 容器盒子

d. 可视化盒模型

可变量的结构与表示

赋值

1
2
3
float a = 0.1;
Person p1 = new Person("Jackson");
p1.salary = 100000;

如何实现上述语义呢?

盒子里的变量

In Racket : substitution-value

1
2
3
4
5
6
#lang typed-plai 

(define-type ExprC)
...
[BoxC (val : Value)]
)

In Java : ref-replacement

1
2
3
4
5
6
7
8
9
10
11
12
class Box<T> {
private T the_value;
Box(T v) {
this.the_value = v;
}
T get() {
return the_value;
}
void set(T v) {
the_value = v;
}
}

前言

本文是6. From Substitution to Environments的实验记录。

计划

  • Define a environment
  • Implement lookup in environment

codes

  1. Define a environment as list.

    1
    2
    3
    (define-type Binding
    [bind (name : symbol) (val : number)])
    (define-type-alias Env (listof Binding))
  2. Implement lookup in environment

    1
    2
    3
    4
    5
    6
    7
    8
    ; DONE : Define lookup
    (define (lookup [for : symbol] [env : Env]) : number
    (cond
    [(empty? env) (error 'lookup "name not found")]
    [else (cond
    [(symbol=? for (bind-name (first env)))
    (bind-val (first env))]
    [else (lookup for (rest env))])]))
  3. Substitution VS Env(1st version)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    ; Error case in our implementation of Env 1st.
    ; Our test case equal to
    ; (define (f1 x) (f2 4))
    ; (define (f2 y) (+ x y))
    ; (f1 3)
    ; If we take a look, we will find error binding that x
    ; is not binded in f2's definition.
    (interp (appC 'f1 (numC 3))
    mt-env
    (list (fdC 'f1 'x (appC 'f2 (numC 4)))
    (fdC 'f2 'y (plusC (idC 'x) (idC 'y)))))
  4. detect error occus

    1
    2
    3
    4
    5
    ; env cross scope
    <appC-interp-bind-in-env>
    (extend-env (bind (fdC-arg fd)
    (interp a env fds))
    env)
  5. Corret last error binding

    1
    2
    3
    4
    5
    ; change env to mt-env
    <appC-interp-bind-in-env>
    (extend-env (bind (fdC-arg fd)
    (interp a env fds))
    mt-env)
  6. Scope in 3 terms

    1. Is it bound?
    1. where?
    1. Does it has parent scope?

前言

有时候,我总在想为什么我做事情总是没有一个清晰的计划,并且按照计划执行各项任务。

这个问题,我想了很久。最后,我找到了一个自己可以接受的理由–我是一个理想主义的意识流实践者。

既然,万物都是遵循因果。所以,我想溯源而上,找寻最初的起点。那么,我是从哪一点开始变成
了一个理想主义者呢?

起点

我眼中的编程语言

坦白说,我是从小学的学习机开始接触的编程语言.古人说一眼万年,这或许就是对我们最初相遇的最好
脚注。直到初中,我才直到那种语言叫做QBASIC.

最初的梦想

曾经的希望

现在的行动

前言声明

我是一个非常个人主义且并非专业vuer.只是通过记录使用手记和源码分析来阐发我对vue核心机制和运行流程的理解和记录。勿cue多谢。

Vue的3大魔法

  1. 依赖通知

  2. 模版求值

  3. 单向绑定

  1. 全屏截图 Shift+Commnand+3

  2. 指定区域截屏 Shift+Commnand+3

  3. 截屏app呼出 Shift+Commnand+5

前言

我本来是想先写完上一篇《基于sodium的FRP解析》,再来编写这篇文章。但是,经过我的debug和trace,以及我之前使用reactivecocoabacon.js的经验。我决定还是先写本文来建立FRP的基本概念框架和基础实现路线图。毕竟,我的目的是让我自己掌握建立FRP系统的基本
概念和技术,有了这些基础就能定制化开发我需要的框架。

全局鸟瞰

  • 增加subscriber、observable、subscription、stream等的概念图。
  • 给出所有关键概念对应的实体的接口设计,以及职责描述
  • 以rx.js为例给出关键实体的数据流分析

简化实现

实体-概念对应关系

实体与接口

是否引入事务性机制(inspired by sodium)

关键实现代码剖析

用例

我先用rx.js实验,然后使用我的实现去逐步替换。

坦克大战(项目地址

前言

为什么要写这篇日志?因为,我觉得有必要将这个问题(FRP)整理为一个有完整体系结构的知识集

基于此,日志的格式和内容将是非常个人化的。因为,它主要是为了解决我自己的知识管理技术总结

形成的日志。

全局概览

类层次关系

与Rx的大致对应(不准确)

类名 rx.js 说明
Cell Rx.BehaviourSubject 表示被观察的会变化的值的容器(cache line of data)
Lazy<A> - 对值类型A进行thunk的容器
Listener - 监听函数容器
Stream<A> Rx.Observable 值的变化瞬时传递管道
Transaction<A> - Emitter的容器(closure simulator)

模拟场景说明

1. 必要资源说明

插件地址 插件名称
github.com/mdempsky/gocode gocode
github.com/uudashr/gopkgs/cmd/gopkgs gopkgs
github.com/ramya-rao-a/go-outline go-outline
github.com/acroca/go-symbols go-symbols
golang.org/x/tools/cmd/guru guru
golang.org/x/tools/cmd/gorename gorename
github.com/derekparker/delve/cmd/dlv dlv
github.com/stamblerre/gocode gocode-gomod
github.com/rogpeppe/godef godef
github.com/ianthehat/godef godef-gomod
github.com/sqs/goreturns goreturns
golang.org/x/lint/golint golint

2. 脚本自动化实现

  1. 思路说明

    • 首先,我们将插件和他们的安装包名建立一个map。

    • 其次,我们对这个map做一个遍历。

    • 将买一个MapEntry<path,pluginName>的key(即path)做split操作,然后根据分片后的数组建立目录结构。

    • 在每一个路径分片数组的末尾执行git clone操作

    • 接着,在成功后进行跳回顶层目录($(GOPATH))。

    • 此时,执行go install pluginName

    • 重复上面的过程直到遍历完毕,跟着再次跳回顶层目录($(GOPATH))。

  2. 实现脚本(Python3)

    install_plugin.pyview raw
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    #!/usr/local/bin/python3
    # -*- coding:utf-8 -*-
    import git
    import os, subprocess
    import shutil

    result = os.popen("echo ~/go")
    res = result.read()
    go_path = res.splitlines()[0]
    go_path_src = go_path + "/src"
    os.chdir(go_path_src)

    # 定义插件字典
    entries = {
    "gocode":"github.com/mdempsky/gocode",
    "gopkgs":"github.com/uudashr/gopkgs",
    "go-outline":"github.com/ramya-rao-a/go-outline",
    "go-symbols":"github.com/acroca/go-symbols",
    "guru":"golang.org/x/tools/cmd/guru",
    "gorename":"golang.org/x/tools/cmd/gorename",
    "dlv":"github.com/derekparker/delve/cmd/dlv",
    "gocode-gomod":"github.com/stamblerre/gocode",
    "godef":"github.com/rogpeppe/godef",
    "godef-gomod":"github.com/ianthehat/godef",
    "goreturns":"github.com/sqs/goreturns",
    "golint":"golang.org/x/lint/golint"
    }

    for name,path in entries.items():
    # 对路径进行分片
    dirs = path.split('/')
    git_name = dirs[-1]
    dirs = dirs[0:-1]
    root = go_path_src
    os.chdir(root)
    for dir_name in dirs:
    dest = root+"/"+dir_name
    if not os.path.exists(dest):
    os.mkdir(dir_name)
    print('mkdir '+ dest)
    root = dest
    print("enter dir "+ os.getcwd())
    os.chdir(root)

    print("current dir "+ os.getcwd())
    clone_path = os.getcwd()+git_name
    if os.path.exists(clone_path):
    shutil.rmtree(clone_path)

    print("git clone "+"https://"+path+".git")
    repo = git.Repo.clone_from("https://"+path+".git",git_name)

3. 代理实现(正解)下文引自格物

GOPROXY 环境变量

终于到了本文的终极大杀器 —— GOPROXY。

我们知道从 Go 1.11 版本开始,官方支持了 go module 包依赖管理工具。

其实还新增了 GOPROXY 环境变量。如果设置了该变量,下载源代码时将会通过这个环境变量设置的代理地址,而不再是以前的直接从代码库下载。

更可喜的是,goproxy.io 这个开源项目帮我们实现好了我们想要的。该项目允许开发者一键构建自己的 GOPROXY 代理服务。同时,也提供了公用的[代理服务] (https://goproxy.io),我们只需设置该环境变量即可正常下载被墙的源码包了:

export GOPROXY=https://goproxy.io

不过,需要依赖于 go module 功能。可通过 export GO111MODULE=on 开启 MODULE。

如果项目不在 GOPATH 中,则无法使用 go get ...,但可以使用 go mod ... 相关命令。

也可以通过置空这个环境变量来关闭,export GOPROXY=

对于 Windows 用户,可以在 PowerShell 中设置:

$env:GOPROXY = "https://goproxy.io"

最后,我们当然推荐使用 GOPROXY 这个环境变量的解决方式,前提是 Go version >= 1.11

最后的最后,七牛也出了个国内代理 goproxy.cn 方便国内用户更快的访问不能访问的包,真是良心。

参考资料