41

支持减、乘,以及除

 4 years ago
source link: https://www.tuicool.com/articles/7neyYnj
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在上一篇文章中,初步搭建了一个输入Common Lisp代码,输出汇编代码的编译器的骨架,实现了二元整数的加法运算。在这个基础上,要想实现减法、乘法,以及除法就是手到擒来的事情了。只需依葫芦画瓢,补充更多的分支情况即可。

我自己模仿着x64的调用约定,规定四则运算的结果始终放在 EAX 这个寄存器中。在稍后给出的代码中,对于减法和除法运算,都是把运算符的左操作数放到 EAX 寄存器中,再从 EAX 中减去或者除掉右操作数。

在摸索除法的汇编代码怎么生成时,遇到了个费解的问题,最后才知道,原来需要把 EAX 寄存器的符号扩展到高位的 EDX 寄存器中去。对于 as 这个汇编器来说,需要用到 CLTD 指令。

最后, jjcc2stringify 两个函数被修改为如下的样子

(defun jjcc2 (expr)
  "支持两个数的四则运算的编译器"
  (cond ((eq (first expr) '+)
         `((movl ,(second expr) %eax)
           (movl ,(third expr) %ebx)
           (addl %ebx %eax)))
        ((eq (first expr) '-)
         `((movl ,(second expr) %eax)
           (movl ,(third expr) %ebx)
           (subl %ebx %eax)))
        ((eq (first expr) '*)
         ;; 将两个数字相乘的结果放到第二个操作数所在的寄存器中
         ;; 因为约定了用EAX寄存器作为存放最终结果给continuation用的寄存器,所以第二个操作数应当为EAX
         `((movl ,(second expr) %eax)
           (movl ,(third expr) %ebx)
           (imull %ebx %eax)))
        ((eq (first expr) '/)
         `((movl ,(second expr) %eax)
           (cltd)
           (movl ,(third expr) %ebx)
           (idivl %ebx)))))

(defun stringify (asm)
  "根据jjcc2产生的S表达式生成汇编代码字符串"
  (format t "        .section __TEXT,__text,regular,pure_instructions~%")
  (format t "        .globl _main~%")
  (format t "_main:~%")
  (dolist (ins asm)
    (cond ((= (length ins) 3)
           (format t "        ~A ~A, ~A~%"
                   (first ins)
                   (if (numberp (second ins))
                       (format nil "$~A" (second ins))
                       (second ins))
                   (if (numberp (third ins))
                       (format nil "$~A" (third ins))
                       (third ins))))
          ((= (length ins) 2)
           (format t "        ~A ~A~%"
                   (first ins)
                   (if (numberp (second ins))
                       (format nil "$~A" (second ins))
                       (second ins))))
          ((= (length ins) 1)
           (format t "        ~A~%" (first ins)))))
  (format t "        movl %eax, %edi~%")
  (format t "        movl $0x2000001, %eax~%")
  (format t "        syscall~%"))

全文完。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK