Fix #96: Make x86 disassem produce code usable by gcc/clang
We make the x86 disassembler produce code that can (almost) be directly used by gcc or clang to produce the same code as produced by the compiler.
This means:
- Make the disassembler print the radix indicator ("#x") by default.
- Add ".intel_syntax noprefix" to tell gcc/clang the syntax being used. This is added only for x86.
- Use
/* ... */
for comments instead of;
. This is done for all archs. We also set*print-right-margin*
to 100 so that we're less likely to wrap long things, or truncate the output. - Increase
*note-column*
for x86 because some instructions can be rather long; this makes the note columns more likely to line up neatly without having some instructions pushing the note column farther right so that they don't line up neatly.
This doesn't solve everything; we still have an issue with printing call
in a way that's accepted by both clang and gcc and so that both clang and gcc produce the same code.
Merge request reports
Activity
Here's an example of the output for the function
(defun bar (x) (declare (double-float x)) (sin x))
6004df40: .intel_syntax noprefix .entry |BAR|(x) /* (function (double-float) (double-float -1.0d0 1.0d0)) */ df58: pop dword ptr [ebp-#x8] df5b: lea esp, [ebp-#x40] df5e: cmp ecx, #x4 /* [:non-local-entry] */ df61: jne L3 df67: mov eax, edx df69: and eax, #x7 df6c: cmp eax, #x7 df6f: jne L5 df75: movzx eax, byte ptr [edx-#x7] df79: cmp eax, #x16 df7c: jne L5 df82: movsd xmm0, [edx+#x1] df87: movsd [ebp-#x1c], xmm0 df8c: lea eax, [#x5f000048] /* fdlibm_sin */ /* No-arg-parsing entry point */ /* [:non-local-entry] */ df92: sub esp, #x8 df95: and esp, #xfffffff0 df9b: movsd xmm0, [ebp-#x1c] dfa0: movsd [ebp-#x24], xmm0 dfa5: movsd xmm0, [ebp-#x24] dfaa: movsd [esp], xmm0 dfaf: call eax /* [6] (SIN X) */ dfb1: fstp qword ptr [ebp-#x14] /* [:internal-error] */ dfb4: movsd xmm0, [ebp-#x14] dfb9: add esp, #x8 dfbc: mov byte ptr [#x28000234], #x0 /* lisp::*pseudo-atomic-interrupted* */ /* [:block-start] */ dfc3: mov byte ptr [#x2800021c], #x4 /* lisp::*pseudo-atomic-atomic* */ dfca: mov edx, #x10 dfcf: add edx, dword ptr [#x28000384] /* x86::*current-region-free-pointer* */ dfd5: cmp edx, dword ptr [#x2800039c] /* x86::*current-region-end-addr* */ dfdb: jbe L0 dfdd: sub edx, dword ptr [#x28000384] /* x86::*current-region-free-pointer* */ dfe3: push eax dfe4: mov eax, edx dfe6: call #x5f000008 /* alloc_overflow_sse2 */ dfeb: mov edx, eax dfed: pop eax dfee: jmp L1 dff0: L0: xchg edx, dword ptr [#x28000384] /* x86::*current-region-free-pointer* */ dff6: L1: mov dword ptr [edx], #x316 dffc: lea edx, [edx+#x7] dfff: movsd [edx+#x1], xmm0 e004: mov byte ptr [#x2800021c], #x0 /* lisp::*pseudo-atomic-atomic* */ e00b: cmp byte ptr [#x28000234], #x0 /* lisp::*pseudo-atomic-interrupted* */ e012: je L2 e014: ud1 ecx, ecx /* Trap 9: Pending interrupt trap */ e017: L2: mov ecx, dword ptr [ebp-#x8] e01a: mov eax, dword ptr [ebp-#x4] e01d: add ecx, #x2 e020: mov esp, ebp e022: mov ebp, eax e024: jmp ecx e026: nop e027: nop e028: nop e029: nop e02a: nop e02b: nop e02c: nop e02d: nop e02e: nop e02f: nop e030: L3: ud1 ecx, edx /* Trap 10: Error trap */ e033: .byte #x02 e034: .byte #x1a /* INVALID-ARGUMENT-COUNT-ERROR */ e035: .byte #x4f /* ECX */ e036: L4: L5:ud1 ecx, edx /* Trap 10: Error trap */ e039: .byte #x02 e03a: .byte #x06 /* OBJECT-NOT-DOUBLE-FLOAT-ERROR */ e03b: .byte #x90 /* EDX */
mentioned in issue #185 (closed)
mentioned in merge request !138 (merged)
mentioned in issue #188
assigned to @rtoy
requested review from @cshapiro
@cshapiro PTAL
- Make the disassembler print the radix indicator ("#x") by default.
The presence of the Lisp style radix indication will cause a syntax error. You can use a
0x
prefix or ah
suffix but not a#x
suffix6004df40: .intel_syntax noprefix
The presence of the address cause a syntax error
.entry |BAR|(x)
This invalid directive will cause an error
dff0: L0: xchg edx, dword ptr [#x28000384] /* x86::*current-region-free-pointer* */
For the sake of the compiler this should be
.L0
on Linux andL0
on Darwin to indicate a local label....
All that aside, the default disassembly output should foremost be for human consumption. Being able to feed this into a compiler is a very laudable goal but to get there from here you are going need to either post-process the output you are generating today or put this behind a flag that disassembles for machine consumption adding all of the needed context in the output a like the constant vector or symbols like T and NIL. To make this amenable to the compiler we will need to specify
.text
and.data
or the ELF type information which you would need for assembling.Since that extra step is needed why burden humans with changes like renaming
;
to/* ... */
and add things like.intel_sytnax noprefix
when that is readily done by a post-processing program or it can be pushed behind a flag? Moreover, a script could automate all of the work to create a .S file that the user can compile without having to know all of the details of what is needed to host code like this outside of a real Lisp.Good points. Then I think the only thing I want to do is change the default to print the (Lisp) radix marker by default. (You can already do this via
disassem:disassemble
, but I thinkdisassemble
should print the radix marker too.Also I'd like to move the note column out a bit on x86 because some instructions extend past that column.
I do have a partial implementation of a script to convert the disassembly to something that gcc or clang will mostly like. I'll add it to the snippets section.
mentioned in issue #96 (closed)