assemblyx86shared-librarieslibcposition-independent-code

Writing and linking shared libraries in assembly 32-bit


I am currently learning assembler for x86 with att syntax. Over the past time I have already written exercise programs without dependencies. Now I wanted to try writing a shared shared-library, as this is what I do in C most of the time.

I thought it may be a good idea to write a simple "test" program, which consists of an, in asm written, test-library and a program, that links to this test-library.

I assembled the library with: as -32 prog.s -o prog.o
and the caller with: as -32 startprog.s -o startprog.o

After I assembled both files, I ran the linker on the library with ld -melf_i386 -fPIE -shared prog.o -o libprog.so
and on the caller ld -melf_i386 startprog.o -L./ -lprog -o startprog

Up to this point everything worked fine. But then I tried to run the program ./startprog, which causes a Segment violation. I re-ran with gdb and set _start as a breakpoint. As soon as I entered r into gdb, to actually start the execution, I was greeted with the same SIGSEGV. It seems to occur in the libc write() function. At least that is, what I can make of this.

The complete output looks like this:

[cediw@cwm10 pC $] gdb ./startprog 
Reading symbols from ./startprog...
(No debugging symbols found in ./startprog)
(gdb) b _start 
Breakpoint 1 at 0x8049020
(gdb) r
Starting program: /home/cediw/dev/asm/re/pC/startprog 
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.

Program received signal SIGSEGV, Segmentation fault.
0xf7f06fe1 in write () from /usr/lib/libc.so.1
(gdb) disas
Dump of assembler code for function write:
   0xf7f06fd0 <+0>: push   %esi
   0xf7f06fd1 <+1>: push   %ebx
   0xf7f06fd2 <+2>: sub    $0x14,%esp
   0xf7f06fd5 <+5>: mov    0x20(%esp),%ebx
   0xf7f06fd9 <+9>: mov    0x24(%esp),%ecx
   0xf7f06fdd <+13>:    mov    0x28(%esp),%edx
=> 0xf7f06fe1 <+17>:    mov    %gs:0xc,%eax
   0xf7f06fe7 <+23>:    test   %eax,%eax
   0xf7f06fe9 <+25>:    jne    0xf7f07010 <write+64>
   0xf7f06feb <+27>:    mov    $0x4,%eax
(gdb) i r
eax            0xf7fa44e0          -134593312
ecx            0xf7fa44e0          -134593312
edx            0x1aa               426
ebx            0x1                 1
esp            0xffffd3f4          0xffffd3f4
ebp            0x0                 0x0
esi            0x0                 0
edi            0x0                 0
eip            0xf7f06fe1          0xf7f06fe1 <write+17>
eflags         0x10282             [ SF IF RF ]
cs             0x23                35
ss             0x2b                43
ds             0x2b                43
es             0x2b                43
fs             0x0                 0
gs             0x0                 0

My test-library looks like this:

# file: prog.s
.section .rodata    
    str: .string "Hallo Welt\n"
    
.section .text
    .globl  test
    .type   test, @function

.macro push_all
    push    %ebx
    push    %ecx
    push    %edx
    push    %edi
    push    %esi
.endm

.macro pop_all
    pop %esi
    pop %edi
    pop %edx
    pop %ecx
    pop %ebx
.endm


test:
    push    %ebp
    movl    %esp, %ebp
    push_all

    movl    %esp, %eax
    addl    $_GLOBAL_OFFSET_TABLE_, %eax
    movl    str@GOTOFF(%eax), %ecx

    movl    $4, %eax
    movl    $1, %ebx
    movl    $11, %edx
    int $0x80
    
    pop_all
    pop %ebp
    ret
    .size   test, .-test

#startprog.s
.section .text
    .globl _start
    .globl test

_start:
    call    test

What exactly am I doing wrong? And are there any resources where I can learn this a bit better? Because currently I am crawling google to find good sources on this.

Thanks and greetings Cedric

Edit: objdump

[cediw@cwm10 pC $] objdump -d -Matt -s startprog

startprog:     file format elf32-i386

Contents of section .interp:
 8048134 2f757372 2f6c6962 2f6c6962 632e736f  /usr/lib/libc.so
 8048144 2e3100                               .1.             
Contents of section .hash:
 8048148 01000000 02000000 01000000 00000000  ................
 8048158 00000000                             ....            
Contents of section .gnu.hash:
 804815c 01000000 01000000 01000000 00000000  ................
 804816c 00000000 00000000                    ........        
Contents of section .dynsym:
 8048174 00000000 00000000 00000000 00000000  ................
 8048184 01000000 00000000 00000000 12000000  ................
Contents of section .dynstr:
 8048194 00746573 74006c69 6270726f 672e736f  .test.libprog.so
 80481a4 00                                   .               
Contents of section .rel.plt:
 80481a8 0cb00408 07010000                    ........        
Contents of section .plt:
 8049000 ff3504b0 0408ff25 08b00408 00000000  .5.....%........
 8049010 ff250cb0 04086800 000000e9 e0ffffff  .%....h.........
Contents of section .text:
 8049020 e8ebffff ff                          .....           
Contents of section .dynamic:
 804af70 01000000 06000000 04000000 48810408  ............H...
 804af80 f5feff6f 5c810408 05000000 94810408  ...o\...........
 804af90 06000000 74810408 0a000000 11000000  ....t...........
 804afa0 0b000000 10000000 15000000 00000000  ................
 804afb0 03000000 00b00408 02000000 08000000  ................
 804afc0 14000000 11000000 17000000 a8810408  ................
 804afd0 00000000 00000000 00000000 00000000  ................
 804afe0 00000000 00000000 00000000 00000000  ................
 804aff0 00000000 00000000 00000000 00000000  ................
Contents of section .got.plt:
 804b000 70af0408 00000000 00000000 16900408  p...............

Disassembly of section .plt:

08049000 <.plt>:
 8049000:   ff 35 04 b0 04 08       pushl  0x804b004
 8049006:   ff 25 08 b0 04 08       jmp    *0x804b008
 804900c:   00 00                   add    %al,(%eax)
    ...

08049010 <test@plt>:
 8049010:   ff 25 0c b0 04 08       jmp    *0x804b00c
 8049016:   68 00 00 00 00          push   $0x0
 804901b:   e9 e0 ff ff ff          jmp    8049000 <.plt>

Disassembly of section .text:

08049020 <_start>:
 8049020:   e8 eb ff ff ff          call   8049010 <test@plt>

It is clearly visible that the linker links libc, even if I try to use -nostdlib

UPDATE

Okay, so I have viewed the output of the command file startprog which tells me, that the runtime was set to c's. I have changed the runtime with patchelf --set-interpreter /lib/ld-linux.so.2 startprog to the linux runtime and it works now. I will post this as an answer to my question. But another, very important question remains: Why did it even link it with the c-runtime?


Solution

  • As stated in the UPDATE, i've got it working by patching the runtime of the ELF with patchelf --set-interpreter /lib/ld-linux.so.2 startprog

    Also as stated, if anyone knows, why it automatically assigned the libc as the runtime, I would be pretty thankful, if they would post the answer. It confuses me to no end any I would like to avoid patching the binary every time.