上一篇,我们发现大多数 6502 指令都可以直接 1:1 翻译成 JS 代码,但除了「跳转指令」。

跳转指令,分无条件跳转、条件跳转。从另一个角度,也可分:

  • 静态跳转:目标地址已知

  • 动态跳转:目标地址运行时才知道

为了让问题更简单,本文只讨论「静态跳转」,并且是在固定的指令之间跳转。

我们用 JXX 表示跳转指令,XXX 表示其他指令:

L1:
XXX
JXX L1 -
XXX
JXX L2 +
XXX
L2:
XXX

这里 JXX L1 跳转到之前的位置,暂且称为「负跳转」。相应的,JXX L2 跳到之后的位置,称为「正跳转」。

正跳转

先来讨论正跳转。因为正跳转只会离终点越来越近,所以简单一些。先看个例子:

    XXX 1
JXX L1 --.
XXX 2 |
JXX L2 --|--.
L1: | |
XXX 3 <-| |
L2: |
XXX 4 <-|

这个分支很简单,可轻松翻译成 JS 代码:

XXX 1
if (...) {
XXX 3
} else {
XXX 2
}
XXX 4

但是,遇到稍复杂的分支,用 if..else.. 就会显得力不从心,因此需要用 break 来控制流程。

然而 break 只能用在循环里 —— 没事,套个空循环就可以:

do {
...
if (...) break // JXX L1
...
if (...) break // JXX L1
...
} while (0)
... // L1:

我们把 do 放在程序顶部,while 放在目标位置之前。这样,用 break 即可实现跳转 —— 退出 while,进入目标位置。

在很多语言里 do..while(0) 都有一些妙用,这是个有趣的语法糖。

当然,如果有多个不同的跳转,就需要嵌套多个 do 了。这时,如何指定 break 对应的层次?

熟悉 JS 的朋友都知道,JS 虽然没有 goto,但 label 的概念还是存在的。因此我们给每个 do 都贴上标签,同时 break 也指明标签:

a1: do {
a2: do {
...
if (...) break a1 // JXX L1
...
if (...) break a2 // JXX L2
...
} while (0) // L2:
...
} while (0) // L1:
...

我们把 do 放在最开头;每个 while(0) 对应一个目标位置。这样就实现了「正跳转」的翻译!

负跳转

现实中,不可能全是正跳转,否则程序一下子就执行到底了。负跳转,则可跳回先前位置,反复执行指令。

对于负跳转,是否也能用类似的方案?看起来好像不难,把 break 换成 continue,就可以回到 do 的后面。

a1: do {                    // L1
...
a2: do { // L2
...
...
if (...) continue a1 // JXX L1
...
} while (0)
...
if (...) continue a2 // JXX L2
...
} while (0)
...

对于这种简单的分支,貌似还行得通。但是对于稍复杂的情况,例如原本就已存在正跳转:

a1: do {
...
if (...) break --.
... |
if (...) break --|
... |
DST | <-.
... | |
} while (0) <-! |
... ???
... |
SRC --!

我们打算从 SRC 跳到 DST 位置 —— 这时的负跳转,又该如何实现?

因为 do..while 是单向的,只能从里面跳出来,无法从外面跳进去。

也许你会说,可以在 DST 处放一个 do。很不幸,这个 do 会和 a1 的 while 结合,完全不符合我们的意图。

简单地说,do..while 只能嵌套,无法交叉。

所以,负跳转很难翻译成 JS 代码。


退一步说,就算能翻译出来,最终也未必适用。因为传统程序,很多是这样的逻辑:

BEGIN:
输入查询
程序逻辑
输出结果
空跑耗时
GOTO BEGIN

这翻译成 JS 就是一个死循环,无法输入,也看不到输出,完全不符合浏览器的线程模型。

因此,还必须对流程进行改造,以一种可控的方式执行。

下一篇,我们讨论如何改造流程。

机器指令翻译成 JavaScript —— No.2 跳转处理的更多相关文章

  1. 【探索】机器指令翻译成 JavaScript

    前言 前些时候研究脚本混淆时,打算先学一些「程序流程」相关的概念.为了不因太枯燥而放弃,决定想一个有趣的案例,可以边探索边学. 于是想了一个话题:尝试将机器指令 1:1 翻译 成 JavaScript ...

  2. 机器指令翻译成 JavaScript —— No.5 指令变化

    上一篇,我们通过内置解释器的方案,解决任意跳转的问题.同时,也提到另一个问题:如果指令发生变化,又该如何应对. 指令自改 如果指令加载到 RAM 中,那就和普通数据一样,也是可以随意修改的.然而,对应 ...

  3. 机器指令翻译成 JavaScript —— No.7 过渡语言

    上一篇,我们决定使用 LLVM 来优化程序,并打算用 C 作为输入语言.现在我们来研究一下,将 6502 指令转换成 C 的可行性. 跳转支持 翻译成 C 语言,可比 JS 容易多了.因为 C 支持 ...

  4. 机器指令翻译成 JavaScript —— No.4 动态跳转

    上一篇,我们用模拟流程的方式,解决了跳转问题. 不过静态跳转,好歹事先是知道来龙去脉的.而动态跳转,只有运行时才知道要去哪.既然流程都是未知的,翻译从何谈起? 动态跳转,平时出现的多吗?非常多!除了 ...

  5. 机器指令翻译成 JavaScript —— No.6 深度优化

    第一篇 中我们曾提到,JavaScript 最终还得经过浏览器来解析.因此可以把一些优化工作,交给脚本引擎来完成. 现代浏览器的优化能力确实很强,但是,运行时的优化终归是有限的.如果能在事先实现,则可 ...

  6. 机器指令翻译成 JavaScript —— 终极目标

    上一篇,我们顺利将 6502 指令翻译成 C 代码,并演示了一个案例. 现在,我们来完成最后的目标 -- 转换成 JavaScript. 中间码输出 我们之所以选择 C,就是为了使用 LLVM.现在来 ...

  7. 机器指令翻译成 JavaScript —— No.3 流程分割

    上一篇 我们讨论了跳转指令,并实现「正跳转」的翻译,但最终困在「负跳转」上.而且,由于线程模型的差异,我们不能 1:1 的翻译,必须对流程进行一些改造. 当初之所以选择翻译,而不是模拟,就是出于性能考 ...

  8. 四十年前的 6502 CPU 指令翻译成 JS 代码会是怎样

    去年折腾的一个东西,之前 blog 里也写过,不过那时边琢磨边写,所以比较杂乱,现在简单完整地讲解一下. 前言 当时看到一本虚拟机相关的书,正好又在想 JS 混淆相关的事,无意中冒出个问题:能不能把某 ...

  9. [书籍翻译] 《JavaScript并发编程》第一章 JavaScript并发简介

    > 本文是我翻译<JavaScript Concurrency>书籍的第一章,该书主要以Promises.Generator.Web workers等技术来讲解JavaScript并 ...

随机推荐

  1. 基于DDD的现代ASP.NET开发框架--ABP系列文章总目录

    ABP相关岗位招聘:给热爱.NET新技术和ABP框架的朋友带来一个高薪的工作机会 ABP交流会录像视频:ABP架构设计交流群-7月18日上海线下交流会的内容分享(有高清录像视频的链接) 代码自动生成: ...

  2. java基础_集合List与Set接口

    List接口继承了Collection的方法  当然也有自己特有的方法向指定位置添加元素   add(索引,添加的元素); 移除指定索引的元素   remove(索引) 修改指定索引的元素   set ...

  3. Matlab 高斯_拉普拉斯滤波器处理医学图像

    前言:本程序是我去年实现论文算法时所做.主要功能为标记切割肝脏区域.时间有点久,很多细节已经模糊加上代码做了很多注释,因此在博客中不再详述. NOTE: 程序分几大段功能模块,仔细阅读,对解决医学图像 ...

  4. .Net Core MVC 网站开发(Ninesky) 2.3、项目架构调整(续)-使用配置文件动态注入

    上次实现了依赖注入,但是web项目必须要引用业务逻辑层和数据存储层的实现,项目解耦并不完全:另一方面,要同时注入业务逻辑层和数据访问层,注入的服务直接写在Startup中显得非常臃肿.理想的方式是,w ...

  5. 再谈C#采集,一个绕过高强度安全验证的采集方案?方案很Low,慎入

    说起采集,其实我是个外行,以前拔过阿里巴巴的客户数据,在我博客的文章:C#+HtmlAgilityPack+XPath带你采集数据(以采集天气数据为例子) 中,介绍过采集用的工具,其实很Low的,分析 ...

  6. JS实现页面进入、返回定位到具体位置

    最为一个刚入职不久的小白...慢慢磨练吧... JS实现页面返回定位到具体位置 其实浏览器也自带了返回的功能,也就是说,自带了返回定位的功能.正常的跳转,返回确实可以定位,但是有些特殊场景就不适用了. ...

  7. windows下 安装 rabbitMQ 及操作常用命令

    rabbitMQ是一个在AMQP协议标准基础上完整的,可服用的企业消息系统.它遵循Mozilla Public License开源协议,采用 Erlang 实现的工业级的消息队列(MQ)服务器,Rab ...

  8. 浅谈Java的throw与throws

    转载:http://blog.csdn.net/luoweifu/article/details/10721543 我进行了一些加工,不是本人原创但比原博主要更完善~ 浅谈Java异常 以前虽然知道一 ...

  9. NPM如何更新到最新版

    参考文章--npm更新到最新版本的方法 其实我们可以这样,随便新建一个文件夹例如:F:\test.按着"shift"键,右键该文件夹,选择"在此处打开命令窗口(W)&qu ...

  10. Form 表单提交参数

    今天因为要额外提交参数数组性的参数给form传到后台而苦恼了半天,结果发现,只需要在form表单对应的字段html空间中定义name = 后台参数名 的属性就ok了. 后台本来是只有模型参数的,但是后 ...