Sign in Join
Wiki copytemporary

Assembler and ABI Resources: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11## The Assembler
22
33The FPC Pascal Compiler translates Pascal source code into assembly language which is then processed by an assembler running as a separate backend. Some other Pascal compilers directly generate object modules or executable programs directly, i.e. they do not require a separate assembler.
44
55An assembler is itself an executable program that translates assembly language into an object module. In most cases the object modules are passed to a linker which then produces an executable program, although in some there are additional stages (code signing for secure operating systems, conversion to a binary for embedded systems and so on).
66
77## The ABI
88
99The interface between an executable program and the underlying operating system is referred to as the Application Binary Interface or ABI. This includes the CPU's operating mode (e.g. whether word and address sizes default to 32 or 64 bits), operand alignment, function calling conventions, system call numbers, and a selection of constants (e.g. file open modes) and structures (e.g. as returned by the stat() function). It is also usually considered to include the format of the object modules, executable and library files.
1010
1111Obviously the ABI is grossly different between operating systems: in general a program compiled for Windows will not run on Linux and vice versa. In addition, however, there is a significant amount of variation between different "flavours" of related operating systems, for example not only are the system call numbers different between SPARC Solaris and SPARC Linux but they are different between SPARC Linux and x86 Linux.
1212
1313## Purpose of this note
1414
1515In most cases FPC uses the GNU assembler ("as" or "gas") as its backend. However, the assembly language syntax expected by this is different for each target CPU, sections below give examples of this. The original incentive for this was because the author (MarkMLl) found that he needed to write an assembler reader for the MIPS processor, and that there was no straightforward comparison of existing formats on which he could base new code.
1616
1717In addition, in some cases the details of the assembly language format or the ABI specification are only available to users registered with the relevant manufacturer, where possible links to unofficial mirrors are given below for casual reference.
1818
1919## Assembler source formats
2020
2121Assembler source emitted by the compiler's code generator has to be (a subset of what is) acceptable to the assembler for the relevant target CPU. In addition, small portions of the RTL (e.g. prt0.as) are of necessity written in assembler, and some Pascal source files (e.g. syscall.inc) contain inline assembler which the compiler has to be able to parse before it is passed to the backend.
2222
2323The list of CPUs below is taken from the compiler as of late 2011. Some of these are no longer supported, or exist merely as minimal stubs.
2424
2525### Alpha
2626
2727This compiler exists only as a minimal stub.
2828
2929### ARM
3030
3131This fragment is from FpSysCall alias FPC_SYSCALL6 in FPC's ./rtl/linux/arm/syscall.inc:
3232
3333`asm`\
3434`  stmfd sp!,{r4,r5,r6}`\
3535`  ldr  r4,param4`\
3636`  ldr  r5,param5`\
3737`  ldr  r6,param6`\
3838`  bl FPC_SYSCALL`\
3939`  ldmfd sp!,{r4,r5,r6}`\
4040`end;`
4141
4242This fragment is from ret_from_fork in Linux's ./arch/arm/kernel/entry-common.S:
4343
4444`ENTRY(ret_from_fork)`\
4545`        bl      schedule_tail`\
4646`        get_thread_info tsk`\
4747`        ldr     r1, [tsk, #TI_FLAGS]            @ check for syscall tracing`\
4848`        mov     why, #1`\
4949`        tst     r1, #_TIF_SYSCALL_TRACE         @ are we tracing syscalls?`\
5050`        beq     ret_slow_syscall`\
5151`        mov     r1, sp`\
5252`        mov     r0, #1                          @ trace exit [IP = 1]`\
5353`        bl      syscall_trace`\
5454`        b       ret_slow_syscall`\
5555`ENDPROC(ret_from_fork)`
5656
5757Note that register names are r0, r1 etc. without a sigil, and that register assignment is right-to-left.
5858
5959### AVR
6060
6161This fragment is from part of fpc's startup code in /rtl/embedded/avr/start.inc:
6262
6363`   _start:`\
6464` {$ifdef CPUAVR_16_REGS}`\
6565`       clr r17`\
6666` {$else CPUAVR_16_REGS}`\
6767`       clr r1`\
6868` {$endif CPUAVR_16_REGS}`\
69-\
69+
7070`       // load stack pointer`\
7171`       ldi r30,lo8(_stack_top)`\
7272`       out 0x3d,r30`\
7373`       ldi r30,hi8(_stack_top)`\
7474`       out 0x3e,r30`\
75-\
75+
7676`       // Initialize .data section`\
7777`       ldi XL,lo8(_data)`\
7878`       ldi XH,hi8(_data)`\
7979`       ldi YH,hi8(_edata)`\
8080`       ldi ZL,lo8(_etext)`\
8181` {$ifdef CPUAVR_16_REGS}`\
8282`       ldi ZH,hi8(_etext)+(0x40) // program memory mapped to $4000 in data space`\
8383` {$else CPUAVR_16_REGS}`\
8484`       ldi ZH,hi8(_etext)`\
8585` {$endif CPUAVR_16_REGS}`
8686
8787Note that register names are r0, r1 etc. without a sigil, and that register assignment is right-to-left.
8888
8989### i386
9090
9191This fragment is from FpSysCall alias FPC_SYSCALL6 in FPC's ./rtl/linux/i386/syscall.inc:
9292
9393`asm`\
9494`        push  %ebx`\
9595`        push  %edx`\
9696`        push  %esi`\
9797`        push  %edi`\
9898`        push  %ebp`\
9999`        push  %ecx`\
100100`        cmp   $0, sysenter_supported`\
101101`        jne   .LSysEnter`\
102102`        movl  %edx,%ebx         // param1`\
103103`        pop   %ecx              // param2`\
104104`        movl  param3,%edx       // param3`\
105105`        movl  param4,%esi       // param4`\
106106`        movl  param5,%edi       // param5`\
107107`        movl  param6,%ebp       // param6`\
108108`        int   $0x80`\
109109`        jmp   .LTail`\
110110`  .LSysEnter:`\
111111`        movl  %edx,%ebx         // param1`\
112112`        pop   %ecx              // param2`\
113113`        movl  param3,%edx       // param3`\
114114`        movl  param4,%esi       // param4`\
115115`        movl  param5,%edi       // param5`\
116116`        movl  param6,%ebp       // param6`\
117117`        call psysinfo`\
118118`  .LTail:`\
119119`        pop   %ebp`\
120120`        pop   %edi`\
121121`        pop   %esi`\
122122`        pop   %edx`\
123123`        pop   %ebx`\
124124`        cmpl  $-4095,%eax`\
125125`        jb    .LSyscOK`\
126126`        negl  %eax`\
127127`        call  seterrno`\
128128`        movl  $-1,%eax`\
129129`  .LSyscOK:`\
130130`end;`
131131
132132This fragment is from ret_from_fork in Linux's ./arch/x86/kernel/entry_32.S:
133133
134134`ENTRY(ret_from_fork)`\
135135`        CFI_STARTPROC`\
136136`        pushl %eax`\
137137`        CFI_ADJUST_CFA_OFFSET 4`\
138138`        call schedule_tail`\
139139`        GET_THREAD_INFO(%ebp)`\
140140`        popl %eax`\
141141`        CFI_ADJUST_CFA_OFFSET -4`\
142142`        pushl $0x0202                   # Reset kernel eflags`\
143143`        CFI_ADJUST_CFA_OFFSET 4`\
144144`        popfl`\
145145`        CFI_ADJUST_CFA_OFFSET -4`\
146146`        jmp syscall_exit`\
147147`        CFI_ENDPROC`\
148148`END(ret_from_fork)`
149149
150150Note that register names are eax, ebx etc. with % as a mandatory sigil, and that register assignment is left-to-right.
151151
152152### IA-64
153153
154154This compiler exists only as a minimal stub.
155155
156156### M68K
157157
158158This compiler exists in FPC v1 and has lain dormant for a while but has since inclusion in FPC 2.x in the end of 2013.
159159
160160### MIPS
161161
162162This fragment is from FpSysCall alias FPC_SYSCALL6 in FPC's ./rtl/linux/mips/syscall.inc:
163163
164164`asm`\
165165`  sw  $4,0($23)`\
166166`  sw  $5,-4($23)`\
167167`  sw  $6,-8($23)`\
168168`  sw  $7,-12($23)`\
169169`  sw  $8,-16($23)`\
170170`  sw  $9,-20($23)`\
171171`  sw  $10,-24($23)`\
172172`  sw  $11,-28($23)`\
173173`  sw  $12,-32($23)`\
174174`  sw  $13,-36($23)`\
175175`  sw  $14,-40($23)`\
176176`  addiu  $23,$23,-44`\
177-\
177+
178178`  move  $2,$4`\
179179`  move  $4,$5`\
180180`  move  $5,$6`\
181181`  move  $6,$7`\
182182`  move  $7,$8`\
183183`  move  $8,$9`\
184184`  lw  $9,0($fp)`\
185-\
185+
186186`  subu  $29,32`\
187187`  sw    $8, 16($29)`\
188188`  sw    $9, 20($29)`\
189189`  syscall`\
190190`  nop`\
191191`  addiu $29,32`\
192-\
192+
193193`  beq $7,$0,.LDone`\
194194`  nop`\
195195`  lui   $8,%hi(fpc_threadvar_relocate_proc)`\
196196`  addiu   $8,%lo(fpc_threadvar_relocate_proc)`\
197197`  lw   $8,0($8)`\
198198`  bne  $8,$0,.LThreaded`\
199199`  nop`\
200200`  lui   $4,%hi(Errno+4)`\
201201`  addiu   $4,%lo(Errno+4)`\
202202`  sw    $2,0($4)`\
203203`  b     .LFailed`\
204204`  nop`\
205205`.LThreaded:`\
206206`  sw   $2,-4($fp)#temp#sw $4`\
207207`  lui   $4,%hi(errno)`\
208208`  addiu   $4,$4,%lo(errno)`\
209209`  jal   $8`\
210210`  nop`\
211211`  lw  $8,-4($fp)`\
212212`  sw  $8,0($2)`\
213213`.LFailed:`\
214214`  li    $2,-1`\
215215`.LDone:`\
216-\
216+
217217`  addiu  $23,$23,44`\
218218`  lw  $4,0($23)`\
219219`  lw  $5,-4($23)`\
220220`  lw  $6,-8($23)`\
221221`  lw  $7,-12($23)`\
222222`  lw  $8,-16($23)`\
223223`  lw  $9,-20($23)`\
224224`  lw  $10,-24($23)`\
225225`  lw  $11,-28($23)`\
226226`  lw  $12,-32($23)`\
227227`  lw  $13,-36($23)`\
228228`  lw  $14,-40($23)`\
229-\
229+
230230`end;`
231231
232232This fragment is from ret_from_fork in Linux's ./arch/mips/kernel/entry.S:
233233
234234`FEXPORT(ret_from_fork)`\
235235`        jal     schedule_tail           # a0 = struct task_struct *prev`\
236-\
236+
237237`FEXPORT(syscall_exit)`\
238238`        local_irq_disable               # make sure need_resched and`\
239239`                                        # signals dont change between`\
240240`                                        # sampling and return`\
241241`        LONG_L  a2, TI_FLAGS($28)       # current->work`\
242242`        li      t0, _TIF_ALLWORK_MASK`\
243243`        and     t0, a2, t0`\
244244`        bnez    t0, syscall_exit_work`\
245-\
245+
246246`FEXPORT(restore_all)                    # restore full frame`\
247247`        .set    noat`\
248248`        RESTORE_TEMP`\
249249`        RESTORE_AT`\
250250`        RESTORE_STATIC`\
251251`FEXPORT(restore_partial)                # restore partial frame`\
252252`        RESTORE_SOME`\
253253`        RESTORE_SP_AND_RET`\
254254`        .set    at`
255255
256256Note that register names are 0, 1 etc. with \$ as a mandatory sigil, and that register assignment is right-to-left; versions of GNU as from 2.18 onwards also support symbolic register names a0, a1 etc. There is a delay slot after branch etc. instructions.
257257
258258### PowerPC
259259
260260This fragment is from FpSysCall alias FPC_SYSCALL6 in FPC's ./rtl/linux/powerpc/syscall.inc:
261261
262262`asm`\
263263`  mr  r0,r3`\
264264`  mr  r3,r4`\
265265`  mr  r4,r5`\
266266`  mr  r5,r6`\
267267`  mr  r6,r7`\
268268`  mr  r7,r8`\
269269`  mr  r8,r9`\
270270`  sc`\
271271`  bns   .LDone`\
272272`  lis   r10,(fpc_threadvar_relocate_proc)@ha`\
273273`  lwz   r10,(fpc_threadvar_relocate_proc)@l(r10)`\
274274`  cmpwi r10,0`\
275275`  bne   .LThreaded`\
276276`  lis   r4,(Errno+4)@ha`\
277277`  stw   r3,(Errno+4)@l(r4)`\
278278`  b     .LFailed`\
279279`.LThreaded:`\
280280`  stw   r3,temp`\
281281`  mflr  r3`\
282282`  mtctr r10`\
283283`  lis   r4,(errno)@ha`\
284284`  stw   r3,retaddress`\
285285`  lwz   r3,(errno)@l(r4)`\
286286`  bctrl`\
287287`  lwz   r4,temp`\
288288`  lwz   r5,retaddress`\
289289`  stw   r4,0(r3)`\
290290`  mtlr  r5`\
291291`.LFailed:`\
292292` li    r3,-1`\
293293`.LDone:`\
294294`end;`
295295
296296This fragment is from ret_from_fork in Linux's ./arch/powerpc/kernel/entry_32.S:
297297
298298`ret_from_syscall:`\
299299`        mr      r6,r3`\
300300`        rlwinm  r12,r1,0,0,(31-THREAD_SHIFT)    /* current_thread_info() */`\
301301`        /* disable interrupts so current_thread_info()->flags can't change */`\
302302`        LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */`\
303303`        /* Note: We don't bother telling lockdep about it */`\
304304`        SYNC`\
305305`        MTMSRD(r10)`\
306306`        lwz     r9,TI_FLAGS(r12)`\
307307`        li      r8,-_LAST_ERRNO`\
308308`        andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_USER_WORK_MASK|_TIF_PERSYSCALL_MASK)`\
309309`        bne-    syscall_exit_work`\
310310`        cmplw   0,r3,r8`\
311311`        blt+    syscall_exit_cont`\
312312`        lwz     r11,_CCR(r1)                    /* Load CR */`\
313313`        neg     r3,r3`\
314314`        oris    r11,r11,0x1000  /* Set SO bit in CR */`\
315315`        stw     r11,_CCR(r1)`\
316316`syscall_exit_cont:`\
317317`        lwz     r8,_MSR(r1)`\
318318`BEGIN_FTR_SECTION`\
319319`        lwarx   r7,0,r1`\
320320`END_FTR_SECTION_IFSET(CPU_FTR_NEED_PAIRED_STWCX)`\
321321`        stwcx.  r0,0,r1                 /* to clear the reservation */`\
322322`        lwz     r4,_LINK(r1)`\
323323`        lwz     r5,_CCR(r1)`\
324324`        mtlr    r4`\
325325`        mtcr    r5`\
326326`        lwz     r7,_NIP(r1)`\
327327`        FIX_SRR1(r8, r0)`\
328328`        lwz     r2,GPR2(r1)`\
329329`        lwz     r1,GPR1(r1)`\
330330`        mtspr   SPRN_SRR0,r7`\
331331`        mtspr   SPRN_SRR1,r8`\
332332`        SYNC`\
333333`        RFI`\
334-\
334+
335335`66:     li      r3,-ENOSYS`\
336336`        b       ret_from_syscall`\
337-\
337+
338338`ret_from_fork:`\
339339`        REST_NVGPRS(r1)`\
340340`        bl      schedule_tail`\
341341`        li      r3,0`\
342342`        b       ret_from_syscall`
343343
344344Note that register names are r0, r1 etc. without a sigil, and that register assignment is right-to-left.
345345
346346### PowerPC-64
347347
348348Similar to PowerPC above.
349349
350350### SPARC
351351
352352This fragment is from FpSysCall alias FPC_SYSCALL6 in FPC's ./rtl/linux/sparc/syscall.inc:
353353
354354`asm`\
355355`        mov     %i0,%g1`\
356356`        mov     %i1,%o0`\
357357`        mov     %i2,%o1`\
358358`        mov     %i3,%o2`\
359359`        mov     %i4,%o3`\
360360`        ld      [%i6+92],%o5`\
361361`        mov     %i5,%o4`\
362362`        ta      0x10`\
363363`        bcc     .LSyscOK`\
364364`        nop`\
365365`        mov     %o0,%l0`\
366366`        sethi   %hi(fpc_threadvar_relocate_proc),%o2`\
367367`        or      %o2,%lo(fpc_threadvar_relocate_proc),%o2`\
368368`        ld      [%o2],%o3`\
369369`        subcc   %o3,%g0,%g0`\
370370`        bne     .LThread`\
371371`        nop`\
372372`        sethi   %hi(Errno+4),%o0`\
373373`        ba      .LNoThread`\
374374`        or      %o0,%lo(Errno+4),%o0`\
375375`.LThread:`\
376376`        sethi   %hi(Errno),%o0`\
377377`        or      %o0,%lo(Errno),%o0`\
378378`        call    %o3`\
379379`        ld      [%o0],%o0`\
380380`.LNoThread:`\
381381`        st      %l0,[%o0]`\
382382`        mov     -1,%o0`\
383383`.LSyscOK:`\
384384`        mov     %o0,%i0`\
385385`end;`
386386
387387This fragment is from ret_from_fork in Linux's ./arch/sparc/kernel/entry.S:
388388
389389`linux_fast_syscall:`\
390390`        andn    %l7, 3, %l7`\
391391`        mov     %i0, %o0`\
392392`        mov     %i1, %o1`\
393393`        mov     %i2, %o2`\
394394`        jmpl    %l7 + %g0, %g0`\
395395`         mov    %i3, %o3`\
396-\
396+
397397`linux_syscall_trace:`\
398398`        add     %sp, STACKFRAME_SZ, %o0`\
399399`        call    syscall_trace`\
400400`         mov    0, %o1`\
401401`        cmp     %o0, 0`\
402402`        bne     3f`\
403403`         mov    -ENOSYS, %o0`\
404404`        mov     %i0, %o0`\
405405`        mov     %i1, %o1`\
406406`        mov     %i2, %o2`\
407407`        mov     %i3, %o3`\
408408`        b       2f`\
409409`         mov    %i4, %o4`\
410-\
410+
411411`        .globl  ret_from_fork`\
412412`ret_from_fork:`\
413413`        call    schedule_tail`\
414414`         mov    %g3, %o0`\
415415`        b       ret_sys_call`\
416416`         ld     [%sp + STACKFRAME_SZ + PT_I0], %o0`\
417-\
417+
418418`        /* Linux native system calls enter here... */`\
419419`        .align  4`\
420420`        .globl  linux_sparc_syscall`\
421421`linux_sparc_syscall:`\
422422`        sethi   %hi(PSR_SYSCALL), %l4`\
423423`        or      %l0, %l4, %l0`\
424424`        /* Direct access to user regs, must faster. */`\
425425`        cmp     %g1, NR_SYSCALLS`\
426426`        bgeu    linux_sparc_ni_syscall`\
427427`         sll    %g1, 2, %l4`\
428428`        ld      [%l7 + %l4], %l7`\
429429`        andcc   %l7, 1, %g0`\
430430`        bne     linux_fast_syscall`\
431431`         /* Just do first insn from SAVE_ALL in the delay slot */`
432432
433433Note that register names are i0, i1 etc. with % as a mandatory sigil, and that register assignment is left-to-right. Registers are windowed, and there is a delay slot after branch etc. instructions.
434434
435435### VIS
436436
437437This compiler exists only as a minimal stub.
438438
439439### x86
440440
441441Refer to i386 above.
442442
443443### x86-64
444444
445445This fragment is from FpSysCall alias FPC_SYSCALL6 in FPC's ./rtl/linux/x86_64/syscall.inc:
446446
447447`asm`\
448448`  movq sysnr, %rax        { Syscall number -> rax.  }`\
449449`  movq param1, %rdi         { shift arg1 - arg5. }`\
450450`  movq param2, %rsi`\
451451`  movq param3, %rdx`\
452452`  movq param4, %r10`\
453453`  movq param5, %r8`\
454454`  movq param6, %r9`\
455455`  syscall                 { Do the system call. }`\
456456`  cmpq $-4095, %rax       { Check %rax for error.  }`\
457457`  jnae .LSyscOK           { Jump to error handler if error.  }`\
458458`  negq  %rax`\
459459`  movq  %rax,%rdx`\
460460`  movq  fpc_threadvar_relocate_proc,%rax`\
461461`  leaq  Errno,%r11`\
462462`  testq %rax,%rax`\
463463`  jne   .LThread`\
464464`  movl  %edx,8(%r11)`\
465465`  jmp   .LNoThread`\
466466`.LThread:`\
467467`  pushq %rdx`\
468468`  movq  (%r11),%rdi`\
469469`  call  *%rax`\
470470`  popq  %rdx`\
471471`  movl  %edx,(%rax)`\
472472`.LNoThread:`\
473473`  movq  $-1,%rax`\
474474`.LSyscOK:`\
475475`end;`
476476
477477This fragment is from ret_from_fork in Linux's ./arch/x86/kernel/entry_64.S:
478478
479479`ENTRY(ret_from_fork)`\
480480`        DEFAULT_FRAME`\
481-\
481+
482482`        LOCK ; btr $TIF_FORK,TI_flags(%r8)`\
483-\
483+
484484`        push kernel_eflags(%rip)`\
485485`        CFI_ADJUST_CFA_OFFSET 8`\
486486`        popf                                    # reset kernel eflags`\
487487`        CFI_ADJUST_CFA_OFFSET -8`\
488-\
488+
489489`        call schedule_tail                      # rdi: 'prev' task parameter`\
490-\
490+
491491`        GET_THREAD_INFO(%rcx)`\
492-\
492+
493493`        RESTORE_REST`\
494-\
494+
495495`        testl $3, CS-ARGOFFSET(%rsp)            # from kernel_thread?`\
496496`        je   int_ret_from_sys_call`\
497-\
497+
498498`        testl $_TIF_IA32, TI_flags(%rcx)        # 32-bit compat task needs IRET`\
499499`        jnz  int_ret_from_sys_call`\
500-\
500+
501501`        RESTORE_TOP_OF_STACK %rdi, -ARGOFFSET`\
502502`        jmp ret_from_sys_call                   # go to the SYSRET fastpath`\
503-\
503+
504504`        CFI_ENDPROC`\
505505`END(ret_from_fork)`
506506
507507Note that register names are rax, rbx etc. with % as a mandatory sigil, and that register assignment is left-to-right.
508508
509509### zSeries (S/390)
510510
511511As of early 2012, IBM's [[ZSeries|zSeries]] (formerly System/390) is not supported by the compiler, refer to [[ZSeries/Part 1]] for the current implementation status. Note that Linux 2.6 probably won't run on anything older than an S/390 G5.
512512
513513#### For the GNU assembler (gas):
514514
515515This fragment is from ret_from_fork in Linux's ./arch/s390/kernel/entry.S:
516516
517517`#define BASED(name) name-system_call(%r13)`\
518-\
518+
519519`        .globl  ret_from_fork`\
520520`ret_from_fork:`\
521521`        l       %r13,__LC_SVC_NEW_PSW+4`\
522522`        l       %r9,__LC_THREAD_INFO    # load pointer to thread_info struct`\
523523`        tm      SP_PSW+1(%r15),0x01     # forking a kernel thread ?`\
524524`        bo      BASED(0f)`\
525525`        st      %r15,SP_R15(%r15)       # store stack pointer for new kthread`\
526526`0:      l       %r1,BASED(.Lschedtail)`\
527527`        basr    %r14,%r1`\
528528`        TRACE_IRQS_ON`\
529529`        stosm   __SF_EMPTY(%r15),0x03   # reenable interrupts`\
530530`        b       BASED(sysc_tracenogo)`\
531-\
531+
532532`sysc_tracenogo:`\
533533`        tm      __TI_flags+2(%r9),_TIF_SYSCALL`\
534534`        bz      BASED(sysc_return)`\
535535`        l       %r1,BASED(.Ltrace_exit)`\
536536`        la      %r2,SP_PTREGS(%r15)     # load pt_regs`\
537537`        la      %r14,BASED(sysc_return)`\
538538`        br      %r1`
539539
540540Note that register names are r0, r1 etc. with % as a mandatory sigil. Older assemblers (below) arranged the operands as ordered in the binary opcode (i.e. register assignment order varies by operation), this might have changed for the GNU assembler resulting in obvious compatibility problems.
541541
542542#### For the IBM assembler:
543543
544544For the purpose of comparison and with minimal comment, here are "Hello, World!" programs compiled with GCC for different targets.
545545
546546`GCCMVS on MUSIC/SP hosted by Sim/390 using the command`\
547-\
547+
548548`gccmvs_v30 -S -o hello.asm ... hello.c`\
549-\
549+
550550`generates this:`\
551-\
551+
552552`LC0     EQU   *`\
553553`        DC    C'Hello, MUSIC/SP!'`\
554554`        DC    X'15'`\
555555`        DC    X'0'`\
556556`        DS    0F`\
557557`        EXTRN @@CRT0`\
558558`* Function main prologue`\
559559`MAIN    PDPPRLG CINDEX=0,FRAME=92,BASER=12,ENTRY=YES`\
560560`        B     FEN0`\
561561`        LTORG`\
562562`FEN0    EQU   *`\
563563`        DROP  12`\
564564`        BALR  12,0`\
565565`        USING *,12`\
566566`PG0     EQU   *`\
567567`        LR    11,1`\
568568`        L     10,=A(PGT0)`\
569569`* Function main code`\
570570`        MVC   88(4,13),=A(LC0)`\
571571`        LA    1,88(,13)`\
572572`        L     15,=V(PRINTF)`\
573573`        BALR  14,15`\
574574`        SLR   2,2`\
575575`        LR    15,2`
576576
577577In the example above, note that registers are identified numerically (e.g. BALR 12,0); it is common to load a macro package which introduces a leading R as a sigil (i.e. BALR R12,R0). The operands are ordered as in the binary opcode (i.e. register assignment order varies by operation), this might have changed for the GNU assembler (see section above) resulting in obvious compatibility problems.
578578
579579`GCC on zSeries Linux hosted by Hercules using the command`\
580-\
580+
581581`gcc -S -o hello.asm hello.c`\
582-\
582+
583583`apparently assuming -march=g5, generates this:`\
584-\
584+
585585`.LC0:`\
586586`       .string "Hello, Linux!"`\
587587`.text`\
588588`       .align  4`\
589589`.globl main`\
590590`       .type   main, @function`\
591591`main:`\
592592`.LFB2:`\
593593`       stm     %r11,%r15,44(%r15)`\
594594`.LCFI0:`\
595595`       basr    %r13,0`\
596596`.L3:`\
597597`       ahi     %r15,-96`\
598598`.LCFI1:`\
599599`       lr      %r11,%r15`\
600600`.LCFI2:`\
601601`       l       %r1,.L4-.L3(%r13)`\
602602`       lr      %r2,%r1`\
603603`       l       %r1,.L5-.L3(%r13)`\
604604`       basr    %r14,%r1`\
605605`       lhi     %r1,0`\
606606`       lr      %r2,%r1`\
607607`       l       %r4,152(%r11)`\
608608`       lm      %r11,%r15,140(%r11)`\
609609`       br      %r4`\
610610`       .align  4`\
611611`.L5:`\
612612`       .long   puts`\
613613`.L4:`\
614614`       .long   .LC0`\
615-\
615+
616616`I think that's still effectively generating code similar to traditional`\
617617`assembler's "using".`
618618
619619`With the explicit instruction to use a later CPU:`\
620-\
620+
621621`gcc -march=z900 -S -o hello.asm hello.c`\
622-\
622+
623623`it generates this:`\
624-\
624+
625625`.LC0:`\
626626`       .string "Hello, Linux!"`\
627627`.text`\
628628`       .align  4`\
629629`.globl main`\
630630`       .type   main, @function`\
631631`main:`\
632632`.LFB2:`\
633633`       stm     %r11,%r15,44(%r15)`\
634634`.LCFI0:`\
635635`       ahi     %r15,-96`\
636636`.LCFI1:`\
637637`       lr      %r11,%r15`\
638638`.LCFI2:`\
639639`       larl    %r2,.LC0`\
640640`       brasl   %r14,puts`\
641641`       lhi     %r1,0`\
642642`       lr      %r2,%r1`\
643643`       l       %r4,152(%r11)`\
644644`       lm      %r11,%r15,140(%r11)`\
645645`       br      %r4`\
646-\
646+
647647`If I'm reading that correctly, it's referring to the string directly`\
648648`without using a register.`
649649
650650## ABI references
651651
652652The list of CPUs etc. is based on those found in the compiler (see above).
653653
654654### Alpha
655655
656656### ARM
657657
658658### AVR
659659
660660Currently only the embedded target is supported by FPC. The compiler follows the register layout [1](https://gcc.gnu.org/wiki/avr-gcc#Register_Layout), frame layout [2](https://gcc.gnu.org/wiki/avr-gcc#Frame_Layout) and calling convention [3](https://gcc.gnu.org/wiki/avr-gcc#Calling_Convention) of the avr-gcc ABI.
661661
662662### i386
663663
664664### IA-64
665665
666666### M68K
667667
668668### MIPS
669669
670670MIPS has several kinds of ABI, including O32, EABI, n32, n64, nowadays the de facto one should be O32. Some ABI document for MIPS O32 ABI can be found in the internet, unfortunately due to the copyright limit, we cannot provide it here. However, this page [4](http://www.linux-mips.org/wiki/MIPSABIHistory) has some useful links.
671671
672672### PowerPC
673673
674674### PowerPC-64
675675
676676### SPARC
677677
678678SPARC is an open architecture. All design documents are freely available (no signup required) from sparc.org and opensparc.net. sparc.org has documents on the 32 bit SPARC version V8 and the 64 bit SPARC version V9. Earlier versions of the architecture, specifically V7 are available on the net (search for Solbourne).
679679
680680You can download the SPARC V8 Architecture Manual here: [5](http://sparc.org/standards/V8.pdf) The SPARC V8 ABI for UNIX is here: [6](http://sparc.org/standards/psABI3rd.pdf)
681681
682682You can download the SPARC V9 Architecture Manual here: [7](http://sparc.org/standards/SPARCV9.pdf) The SPARC V9 ABI for UNIX is here: [8](http://sparc.org/standards/SCD.2.4.1.ps.Z) Newer versions than V9 are available on opensparc.net.
683683
684684### VIS
685685
686686### x86
687687
688688### x86-64
689689
690690### zSeries (S/390)
691691
692692The classic IBM operating systems, particularly when running on older hardware (i.e. preceding the S/390 G5) historically adopt a programming style which passes function parameters in registers and blocks of memory rather than using a stack.
693693
694694For Linux on a 32-bit S/390, "The first 5 integer (char, short, int, long, long long) and pointer parameters are passed in registers R2, R3, R4, R5 and R6. ... long long parameters are passed in register pairs. Structures of 1, 2, 4 or 8 bytes are passed as integers. ... the first 2 floating point parameters are passed in F0 and F2. ... All other parameters are passed on the stack. If the return value is not an integer, pointer, float, double or 1, 2, 4 or 9-byte structure, a "hidden" parameter in R2 will contain the address of the return area." [9](http://linuxvm.org/present/SHARE99/S8139db.pdf)
695695
696696## Other resources
697697
698698As a general point, there's some useful thoughts on binary disassembly at <http://chdk.wikia.com/wiki/GPL_Disassembling> for situations where IDA or equivalent aren't available.
699699
700700---
701701*From the Free Pascal wiki, page "Assembler and ABI Resources", as it stood on 2022-06-18 after a change by Alextp, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
702702Category: FPC internals

Back to history