views:

26

answers:

1

I am creating an i386 ELF executable that needs to import a function from libc6. (It's printf, by the way.)

I have created a very small ELF executable that prints "Hello, world!" to the console by using the Linux kernel interrupt 0x80. This is not optimal and I would like to have the application make use of libc instead.

Here is what I have so far: (credit to this page for most of the structure alignment code.)

BITS 32

            org     0x08048000

ehdr:                                                 ; Elf32_Ehdr
            db      0x7F, "ELF", 1, 1, 1, 0         ;   e_ident
    times 8 db      0
            dw      2                               ;   e_type
            dw      3                               ;   e_machine
            dd      1                               ;   e_version
            dd      _start                          ;   e_entry
            dd      52
            dd      0                               ;   e_shoff
            dd      0                               ;   e_flags
            dw      52
            dw      32
            dw      1                               ;   e_phnum
            dw      0                               ;   e_shentsize
            dw      0                               ;   e_shnum
            dw      0                               ;   e_shstrndx

;   this is the header for the code section

            dd      1                               ;   p_type
            dd      0                               ;   p_offset
            dd      $$                              ;   p_vaddr
            dd      $$                              ;   p_paddr
            dd      filesize                        ;   p_filesz
            dd      filesize                        ;   p_memsz
            dd      5                               ;   p_flags
            dd      0x1000                          ;   p_align

_start:

            ; We want to print the string

    mov eax,4            ; 'write' system call
    mov ebx,1            ; file descriptor 1 = screen
    mov ecx,teststr      ; string to write
    mov edx,14           ; length of string to write
    int 80h              ; call the kernel

    ; Terminate program
    mov eax,1            ; 'exit' system call
    mov ebx,0            ; exit with error code 0
    int 80h              ; call the kernel

_stringtable:

            teststr db "Hello, world!",10,0

filesize      equ     $ - $$

I think I need to add another program header for imports, but I really don't know - nor am I familiar with the format of the contents of that section.

A: 

If you're willing to let the linker do its job, this is enough (GAS syntax; compile with gcc hello.s):

        .text
        .globl main
        .type main, @function
main:
        movl    .LC0, %eax
        pushl   %eax
        call    puts
        xorl    %eax, %eax
        ret
        .size main, .-main
.LC0:
        .asciz  "Hello, world!"

(Technically .LC0 should be put into .rodata but I can't remember exactly how you do that and I'm not on my Linux box right now. Also, this doesn't maintain any stack pointer alignment, which shouldn't be a problem for a toy program like this, but I make no promises.)

If you really want to construct the entire executable by hand, first read this book: http://www.iecc.com/linker/ Then you'll need to read the ELF specification, the System V generic ABI, and the x86-32 psABI supplement; these can all be found here: http://refspecs.freestandards.org/ . Then, use readelf, objdump, and/or hexdump to dismantle the executable image you get from compiling the above and work out how it's constructed.

Zack