2011-11-14 12 views
10

Why do virtual memory addresses for linux binaries start at 0x8048000?をフォローすると、なぜはld -eのデフォルト以外のエントリポイントを使用できないのですか?ELFエントリポイント0x8048000が "ld -e"オプションで変更できないのはなぜですか?

私がそうした場合、デフォルトエントリーポイントの近くにあるアドレスの場合でも、戻りコード139でsegmentation faultが得られます。どうして?

EDIT:

私は質問をより具体的になります。

 .text 
     .globl _start  
_start: 
     movl $0x4,%eax  # eax = code for 'write' system call 
     movl $1,%ebx   # ebx = file descriptor to standard output 
     movl $message,%ecx # ecx = pointer to the message 
     movl $13,%edx   # edx = length of the message 
     int $0x80   # make the system call 
     movl $0x0,%ebx  # the status returned by 'exit' 
     movl $0x1,%eax  # eax = code for 'exit' system call 
     int $0x80   # make the system call 
     .data 
     .globl message 
message:   
     .string "Hello world\n" # The message as data 

私はas program.s -o program.oでこれをコンパイルしld -N program.o -o programと静的にリンクする場合は、テキストのVirtAddrとしてreadelf -l programショーを0x0000000000400078セグメントと0x400078エントリポイントとして。実行すると、 `こんにちは、世界は」印刷されています。

をしかし、私は、プログラムがreadelf -lでそれを点検することになりました二つの異なるヘッダを示しています。killedになります(4バイトでテキストセグメントとエントリポイントを移動)ld -N -e0x400082 -Ttext=0x400082 program.o -o programとリンクしようとすると、タイプLOAD0x0000000000400082で1と0x00000000004000b0 1つ。

の私は0x400086をしようとすると、それはすべての作品、そして唯一のLOADのセクションがあります。

  1. ここで何が起こっている?
  2. どのメモリアドレスを選ぶことができますか?どのメモリアドレスを選ぶことができないのですか?

ありがとう。

+0

私もリンカスクリプトでのエントリポイントを修正することができました:http://stackoverflow.com/a/30536800/895245 –

答えて

24

なぜ私はLDあなたは確か缶

-e LDでデフォルト以外のエントリポイントを使用することはできません。これは、

int foo(int argc, char *argv[]) { return 0; } 

gcc main.c -Wl,-e,foo 

は、実行がメインから開始しないため、機能しません。それはcrt0.o(glibcの一部)からリンクされ、ダイナミックリンクなどのものが適切に起動するように手配する_startで始まります。 _startfooにリダイレクトすると、glibcの初期化に必要なものすべてがバイパスされたため、動作しません。

しかし、ダイナミックリンクは必要なく、glibcが通常どんなことをしても構わない場合は、必要に応じてエントリポイントの名前を付けることができます。例:

#include <syscall.h> 

int foo() 
{ 
    syscall(SYS_write, 1, "Hello, world\n", 13); 
    syscall(SYS_exit, 0); 
} 

gcc t.c -static -nostartfiles -Wl,-e,foo && ./a.out 
Hello, world 

ああ、この質問のあなたのタイトルはあなたの実際の質問(悪いアイデア(TM))と一致しません。

タイトルの質問に答えるには、確かにの実行ファイルがリンクされているアドレスを変更してください。デフォルトでは、ロードアドレスは0x8048000(32ビットのみ、64ビットのデフォルトは0x400000)です。

簡単に変更できます。0x80000にリンク線にを追加します。

更新:

しかし、私は(4つのバイトによってテキストセグメントとエントリポイントを移動)LD -N -e0x400082 -Ttext = 0x400082 program.o -oプログラムにリンクしようとすると、プログラムは、意志殺される

さて、(4).textセクションアライメント制約に違反することなく0x400082Ttextを割り当てることは不可能です。 .textアドレスは少なくとも4バイトの境界に揃えておく必要があります(または必要な配置を.textに変更してください)。

開始アドレスを0x400078,0x40007c、0x400080、0x400084、...、0x400098に設定し、GNU-ld 2.20.1を使用すると、プログラムが動作します。

しかし、binutilsの現在のCVSスナップショットを使用すると、プログラムは0x400078、0x40007c、0x400088、0x40008cで動作し、0x400080,0x400084,0x400090、0x400094、0x400098の場合はKilledになります。これはリンカのバグかもしれませんが、私は他のいくつかの制約に違反しています。この時点で

、あなたが本当に興味を持っている場合、私は、binutilsのソースをダウンロードするldを構築し、正確には1つではなく、2つのPT_LOADセグメントを作成するために原因を考え出す示唆しています。

アップデート2:

オーバーラップのLMAとのセクションの強制新しいセグメント。

Ah!つまり、.dataを移動させる必要があるということです。これは、作業の実行を行います

ld -N -o t t.o -e0x400080 -Ttext=0x400080 -Tdata=0x400180 
+0

私はより良い例を作るために私の質問を更新しました期待どおりに動かないものの – nh2

+0

ありがとう、素晴らしい答え、私はアライメントを考慮しなかった。 – nh2

+0

git bisectを使ってbinutils 2.20と2.21の間で変更を見つけて、あなたが記述した変更を導入しました。 "elf.c(_bfd_elf_map_sections_to_segments):重複するLMAを持つセクションの新しいセグメントを強制的に呼び出す" (http://repo.or.cz/w/binutils.git/commit/278c98e2ff1c95c8ad9579755abda467ea2bc1b4) – nh2

関連する問題