【问题标题】:Would there ever be a reason to write code in pure binary?有没有理由用纯二进制编写代码?
【发布时间】:2011-01-18 23:36:46
【问题描述】:

是否存在 ASM 不够底层的情况?毕竟汇编器还是要组装的。有没有人用二进制写过程序?我只是想知道是否有理论上的理由表明这样做可能是实用的,或者即使在现代计算机上也是可能的。

【问题讨论】:

  • 也许你应该向 Intel/AMD 的人提出这个问题。

标签: language-agnostic binary computer-science


【解决方案1】:

早在 1997 年,我在学校时曾在 TI-83 计算器上执行此操作,但无法使用链接电缆。

通常在那个时候,你只需编写一个汇编程序,使用 TASM 构建它,然后通过链接电缆将其传输到计算器。但是如果我很无聊,想把一些小东西放在一起,我已经记住了足够多的字节指令,以便能够为某些事情输入它们。

旁注当然,如果程序中存在错误,这很有趣,因为它很容易损坏整个计算器的 RAM。因此,您将不得不按住 ON 按钮和/或取出 AAA 电池,并希望这足以恢复计算(不包括内存中的任何程序)。否则要进行硬重置,您将不得不使用螺丝刀拧下特殊的备用电池。好时光……

【讨论】:

  • 这个的简短版本(实际上是所有真正的答案):当没有工具可以为你做这件事时。
【解决方案2】:

历史原因:您运行的机器需要在前面板上切换启动代码。 (是的,这已经完成了。通常在前几代机器中。)

不是你在寻找的现代原因:当你编写汇编程序时,你必须弄清楚这个过程。

【讨论】:

  • 还有很多其他情况,编写汇编程序实际上不/不应该涉及以二进制形式编写任何函数/程序。
  • @Potatoswatter:除非您正在编写第一个汇编,否则您不会用机器代码编写汇编。但是必须手(或头)翻译足够的代码来知道汇编应该做什么。我支持答案。
  • 这是在非常非常早期的个人计算机中完成的。我看到了对 IMSAI 计算机的评论,称赞它的前面板上有拨片开关,比 Altair 8800 的开关好很多。 (IIRC,也有评论称赞该套件易于组装,因为评论者只需将他的示波器拿出一次。)然而,那是不久前的事了。
  • @David:即使是套件 PC 也比我早了几年;我从来没有真正这样做过。虽然我一直在玩弄构建一个微控制器板来支持支持那个操作之王。
【解决方案3】:

你知道了——如果没有 [dis]assembler 可用的话。我一直处于固件黑客攻击的情况,我花了足够的时间查看原始 PowerPC 指令流,以便能够识别和手动组装几种指令。 (我最终移植了一个反汇编程序:http://homepage.mac.com/potswa/source/DisDave.sit,如果你能设法安装它。)

有些 ISA 比其他的要简单得多。 RISC 遵循简单的格式,并且很容易定位自己,因为指令通常长度相同并且与字边界对齐。而 x86-64 则充满了变长编码和前缀码。

FPGA项目或涉及自定义电路时,设计某种指令流并将其手动编码为二进制是很常见的。

【讨论】:

    【解决方案4】:

    当您手动破解二进制格式时,就像 A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux 所做的那样。

    【讨论】:

      【解决方案5】:

      动态代码生成:

      如果您要解决一个非常简单的问题,并且性能很重要,那么分析问题空间并动态生成一个专门的函数来解决问题通常是一个好主意。

      一个实际示例:稀疏矩阵的高性能数学。

      这通常涉及将数字数组相乘数千到数百万次。由于许多矩阵元素可能为零或一,因此如果删除所有琐碎的乘法,您可以节省大量时间。

      为此,一个小的代码生成器可以分析矩阵并动态生成用于矩阵算术的机器代码。如何做到这一点可以从使用 JIT 库(或内置语言功能)到非常简单的方案。

      对于稀疏矩阵乘法的情况,您只需将针对不同情况的预构建代码 sn-ps 粘合在一起即可获得出色的性能。这可以在 50 行 C 代码中完成。

      【讨论】:

        【解决方案6】:

        当我在海军服役期间(大约在 1986 年左右)接受训练时,我们有一台计算机,用于学习电子故障排除,而不是编程故障排除,它是通过在计算机前面输入二进制信息来编程的,我们必须根据结果以及硬件故障排除告诉教练他们在机器上发生了什么故障。据我所知,周围可能还有一台这样的机器。

        我希望我能找到它的源代码,我实际上为机器编写了一个模拟器,并为机器编写了一个语言编译器。使用 1024 字节的内存可以完成多少工作,真是令人惊讶! :)

        【讨论】:

          【解决方案7】:
          1. 必须利用未记录的操作码(在几个现代处理器上仍然存在!) 不久前在基于 6502 的处理器上。
          2. 使用微控制器将程序刷入自制电路时。如今,微控制器可用于各种用途。

          【讨论】:

            【解决方案8】:

            我记得读过 Woz 用机器语言编写了第一个 Apple BASIC(Apple I?Apple II?)。在他们拥有存储设备之前,您需要在监视器中输入十六进制代码。

            【讨论】:

              【解决方案9】:

              即使您发现自己跳过汇编程序并直接使用机器代码,您也不会使用二进制,而是使用十六进制。

              在学校里,我不得不在没有汇编程序的情况下使用调试器修补内存中的代码。虽然很有趣,但这是一项除了嵌入式系统调试之外几乎没有任何价值的技能。

              另外,考虑到汇编中使用的操作码助记符应该与实际操作码具有 1:1 的对应关系(因此称为“助记符”),因此您将无法通过手动敲出机器码来做任何事情不能在汇编中做。汇编器的作用是将助记符转换为操作码(还确定应使用特定指令的哪个版本——例如立即与间接 MOV)、将标签转换为地址以及类似的任务。

              很高兴知道汇编器内部发生了什么,但这几乎永远不会出现,除非您正在寻找汇编器中的错误,破解嵌入式小工具或 MacGyvering 以摆脱非常非常奇怪的情况.

              【讨论】:

              • 没有区别。十六进制(或八进制,我被告知许多老前辈更喜欢(不同的字长,'ya ken?))只是二进制速记。
              • 太阳很热,水很湿。但是,您更愿意输入“01011010”还是“5A”?另外,我还没有看到可以让你输入二进制文件的调试器;我见过的每个人都需要十六进制或(呃)八进制输入。
              【解决方案10】:

              在世界末日后的世界里,所有的键盘和显示器都被摧毁了,而将俄罗斯方块编程到计算机中的唯一方法是通过前面板上的切换开关,是的。

              但是说真的,为什么会有人想做这样的事情呢?

              编辑:显然有些人设计的处理器必须以二进制编程,直到他们可以在他们的处理器上运行汇编程序,但他们只是一小部分人。

              【讨论】:

              • 首先你需要找到一台面板上有拨动开关的电脑。我记得一百万美元的 CDC Cyber​​ 大型机。它有开关,但你必须先找到合适的柜子,然后打开门。它们是:60 位字的 60 次切换。啊回忆。
              • 我的第一份付费编程工作是在 Burroughs 1800 上,它有开关和闪烁的灯。当我们升级到 Burroughs 5900 时,我们失去了切换开关和闪烁的灯,我们不知道计算机在做什么。是的……回忆。
              • 回忆,独自一人在闪烁的灯光下,回到过去,那时有更多的切换。我记得,时间打卡是奢侈品,调试让你发疯。 (嗯,我个人没有。)
              • 嘿!我不认为处理器设计者用二进制程序来引导新系统。他们肯定会交叉编译。
              • 交叉编译是当今流行的方式,但在早期情况有所不同。
              【解决方案11】:

              我的 8 位 Atari 没有任何汇编程序,所以我直接编写了机器代码。要从 BASIC 开始代码,您可以将代码编写为十进制数据字节或字符串。 (是的,您实际上可以在字符串中编写代码,您无法输入的 256 中唯一的字符代码是 155 - 用于返回的代码。幸运的是,没有具有该值的 6502 机器代码指令,所以它只是当分支恰好向后 101 个字节(-101 = 155)时出现问题。)

              我还记得一段常见的启动计时器的代码:

              104 (pla)
              169, 7 (lda #7)
              162, 6 (ldx #6)
              160, 10 (ldy #10)
              76, 92, 228 (jmp 0xE45C)
              

              近年来,我参加了一些尺寸优化装配比赛。尽管大部分代码都是汇编代码,但您仍然必须确切地知道汇编器生成了哪些指令,以便知道它们有多少字节。此外,有时您会使用一些技巧,例如将某些字节用作数据和代码,或者将某些字节用作不同的指令,具体取决于您是输入第一个字节还是在指令中间输入。然后你把指令写成数据字节在汇编代码的中间。

              【讨论】:

                【解决方案12】:

                您有时会受益于使用原始机器代码,而不仅仅是汇编语言。例如,考虑通过电子邮件发送二进制文件,但使用不知道如何解码附件的电子邮件程序。有一次,一些人编写了可以解码附件其余部分的小程序,但程序中的所有内容都是可打印的字符。因此,您解码附件,将电子邮件正文保存为whatever.com,然后执行它。它会解码附件并编写一个二进制文件,然后你可以执行。

                再举一个例子,几年前在 Fidonet 上遇到了一个相当简单的挑战:编写一个程序,它只打印出一个每次运行时递增的数字——但是(让它变得棘手的部分)它不允许使用任何外部文件或其他存储来完成这项工作。为了不让这变得太无聊,这也是一种代码高尔夫之类的事情,尽管测量的大小是可执行字节,而不是源代码。这个挑战的相当多的条目使用了自我修改代码,这些代码在很大程度上取决于指令的编码方式等等。

                稍等片刻,我发现我仍然有我尝试的源代码:

                .model tiny,c
                .286
                .code
                .startup
                main proc
                    mov     si,offset count
                    inc     byte ptr [si]
                    mov     al, [si]
                    mov     bx,4090h
                    shr     al, 4
                    call    convert
                    lodsb
                    and     al,0fh
                    mov     byte ptr end_convert, 08bh
                convert:
                    add     al,bl
                    daa
                    adc     al,bh
                    daa
                    int     29h
                end_convert:
                    ret
                    db      0d6h
                ;    mov     dx, si
                    mov     ah,3ch
                    xor     cx, cx
                    int     21h
                    xchg    bx, ax
                    mov     dx,offset main
                    mov     cx,offset the_end - offset main
                    int     21h
                    ret
                main endp
                
                count:
                        db 0
                name:
                        db 'c.com', 0
                the_end:
                    end
                

                我最好现在就辞职,在我对任何人中风发作负责之前(希望我不会太晚......)

                【讨论】:

                  【解决方案13】:

                  对于一个大学项目,我必须用 VHDL(一种硬件描述语言)设计一个简化的微控制器。为了测试它,我用二进制编写了一个非常简单的程序,因为这是将程序输入模拟微控制器的最方便的方法。

                  【讨论】:

                    【解决方案14】:

                    过去从二进制文件到汇编程序来理解转储的情况并不少见。

                    但不使用汇编程序?我想不出任何理由。 Assembler 已经在对裸机进行编程。唯一的好处是为实际(二进制)指令启用诸如“add”之类的标签。等等

                    【讨论】:

                      【解决方案15】:

                      好吧,如果您是芯片开发人员,您可以使用十六进制在 RAM 或 ROM 中编写一些基本的引导加载指令,而不是使用汇编程序。我已经为我写的软核这样做了。

                      实际上,在你完成之后,下一步就是用 Perl 或其他东西编写一个基本的汇编程序。

                      【讨论】:

                        【解决方案16】:

                        如果您正在创建解释器。也许你已经完成了解释器,但没有完成解析器。您可以通过用纯二进制编写要解释的程序来测试解释器。

                        【讨论】:

                          【解决方案17】:

                          新团队成员的欺凌仪式。

                          【讨论】:

                            【解决方案18】:

                            一个非常酷的例子是这个著名的多语言,它是一个有效的 DOS .COM 文件,因为它的源代码中的 ASCII 兼作二进制 x86 指令! http://ideology.com.au/polyglot/polyglot.txt

                            更多无聊的例子...

                            许多处理器将 ISA 指令实现为更原始的微指令序列(基本上是数据路径控制信号的集合),这些微指令在微码 ROM 中“微编码”。

                            对于足够简单的处理器,您可以直接以二进制形式编写微代码,而不是从助记语言汇编它。或者,如果您正在对处理器进行逆向工程,您可能不知道它的微指令集,而只需要猜测微指令的格式……在这种情况下,您可能也在使用二进制文件。无论哪种方式,这都比汇编语言级别低。

                            有时,6502 等旧处理器的代码使用未记录的指令,这些指令没有官方助记符,因此您必须编写二进制值而不是汇编指令。

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 1970-01-01
                              • 2013-02-13
                              • 1970-01-01
                              • 1970-01-01
                              • 2011-03-31
                              • 1970-01-01
                              • 2011-02-02
                              • 2017-02-28
                              相关资源
                              最近更新 更多