1.从哪里开始
我们根据伪指令的注册顺序先从md_pseudo_table开始一个个分析
const pseudo_typeS md_pseudo_table[] =
{
#if !defined(OBJ_AOUT) && !defined(USE_ALIGN_PTWO)
{"align", s_align_bytes, 0},
#else
{"align", s_align_ptwo, 0},
#endif
{"arch", set_cpu_arch, 0},
#ifndef I386COFF
{"bss", s_bss, 0},
#endif
{"ffloat", float_cons, 'f'},
{"dfloat", float_cons, 'd'},
{"tfloat", float_cons, 'x'},
{"value", cons, 2},
{"slong", signed_cons, 4},
{"noopt", s_ignore, 0},
{"optim", s_ignore, 0},
{"code16gcc", set_16bit_gcc_code_flag, CODE_16BIT},
{"code16", set_code_flag, CODE_16BIT},
{"code32", set_code_flag, CODE_32BIT},
{"code64", set_code_flag, CODE_64BIT},
{"intel_syntax", set_intel_syntax, 1},
{"att_syntax", set_intel_syntax, 0},
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
{"largecomm", handle_large_common, 0},
#else
{"file", (void (*) (int)) dwarf2_directive_file, 0},
{"loc", dwarf2_directive_loc, 0},
{"loc_mark_labels", dwarf2_directive_loc_mark_labels, 0},
#endif
#ifdef TE_PE
{"secrel32", pe_directive_secrel, 0},
#endif
{0, 0, 0}
};
由于我们默认使用i386平台和elf目标格式,则.align 4代表对齐到4字节边界,即使用{"align", s_align_bytes, 0}.
也有其他平台上指对齐2^4字节边界,使用{"align", s_align_ptwo, 0}。处理函数的名字也反映这种不同。
2.align的语法
.align border,fill,max
border:对齐到多少字节边界,必须为2的幂
fill:对齐时地址空间需要扩展,扩展部分的内容要被填充,fill就是用于填充的模式(字符或数)
max:如果对齐扩展的长度超过max,则不对齐
这里fill和max都不是必须的,默认为0
举例
.align 4//对齐到4字节边界
.align 8,'c'//对齐到八字节边界,用'c'字符扩充填充部分
.align 16,'a',8//如果扩展部分超过8就不对齐
3.用例
下面的阅读是基于如下的情景展开的
.text//代码段
...
.align 4
...
4.s_align_bytes
/* Handle the .align pseudo-op on machines where ".align 4" means
align to a 4 byte boundary. */
void
s_align_bytes (int arg)
{
s_align (arg, 1);
}
从上面知arg==0
5.解析border参数
s_align_bytes ->s_align
/* Handle the .align pseudo-op. A positive ARG is a default alignment
(in bytes). A negative ARG is the negative of the length of the
fill pattern. BYTES_P is non-zero if the alignment value should be
interpreted as the byte boundary, rather than the power of 2. */
#define ALIGN_LIMIT (stdoutput->arch_info->bits_per_address - 1)
static void
s_align (int arg, int bytes_p)
{
unsigned int align_limit = ALIGN_LIMIT;//32位平台是31位
unsigned int align;
char *stop = NULL;
char stopc = 0;
offsetT fill = 0;
int max;
int fill_p;
if (flag_mri)//忽略
stop = mri_comment_field (&stopc);
if (is_end_of_line[(unsigned char) *input_line_pointer])//没有任何参数
{
if (arg < 0)
align = 0;
else
align = arg; /* Default value from pseudo-op table. *///缺省值0
}
else
{
align = get_absolute_expression ();//否则计算border值
SKIP_WHITESPACE ();//跳过后面的空格如果有的话
}
if (bytes_p)//从前面知是1,则需要计算log2(border)
{
/* Convert to a power of 2. */
if (align != 0)
{
unsigned int i;
for (i = 0; (align & 1) == 0; align >>= 1, ++i)
;
if (align != 1)
as_bad (_("alignment not a power of 2"));
align = i;// 2^align==border
}
}
if (align > align_limit)//超过可能的最大值,warn
{
align = align_limit;
as_warn (_("alignment too large: %u assumed"), align);
}
6.解析fill和max
s_align_bytes ->s_align
if (*input_line_pointer != ',')// 如果后面不是',',例如.align 4
{
fill_p = 0;
max = 0;
}
else
{
++input_line_pointer;//跳过','
if (*input_line_pointer == ',')//仍然是',',则没有fill,例如.align 4,,2
fill_p = 0;//没有fill
else
{
fill = get_absolute_expression ();//解析fill
SKIP_WHITESPACE ();//跳过可能的空格
fill_p = 1;//有fill
}
if (*input_line_pointer != ',')//.align 4,'c'
max = 0;//没有max
else
{
++input_line_pointer;//跳过','
max = get_absolute_expression ();//解析max
}
}
7. 执行实质的do_align
s_align_bytes ->s_align
if (!fill_p)//没有fill pattern
{
if (arg < 0)//arg小于0是需要fill
as_warn (_("expected fill pattern missing"));
do_align (align, (char *) NULL, 0, max);//.align 4
}
8.do_align
s_align_bytes ->s_align->do_align
/* Guts of .align directive. N is the power of two to which to align.
FILL may be NULL, or it may point to the bytes of the fill pattern.
LEN is the length of whatever FILL points to, if anything. MAX is
the maximum number of characters to skip when doing the alignment,
or 0 if there is no maximum. */
static void
do_align (int n, char *fill, int len, int max)
//n是对齐边界的2的幂,fill指向填充模式,len模式长度,max为对齐最大能扩展的空间
{
if (now_seg == absolute_section)// 当前节是绝对节,则不需要fill
{
if (fill != NULL)
while (len-- > 0)
if (*fill++ != '\0')
{
as_warn (_("ignoring fill value in absolute section"));
break;
}
fill = NULL;
len = 0;
}
#ifdef md_flush_pending_output
md_flush_pending_output ();//无定义
#endif
#ifdef md_do_align
md_do_align (n, fill, len, max, just_record_alignment);//md->machine dependency体系相关
#endif
9.调用体系结构相关的do_align操作md_do_align
s_align_bytes ->s_align->do_align->md_do_align
#define md_do_align(n, fill, len, max, around) \
if ((n)//n>0 \
&& !need_pass_2//是第一遍 \
&& optimize_align_code//i386为1 \
&& (!(fill)//没有填充模式 \
|| ((char)*(fill) == (char)0x90 && (len) == 1))//或填充模式是机器指令nop\
&& subseg_text_p (now_seg))//是代码段 \
{ \
frag_align_code ((n), (max));//对齐 \
goto around;//跳出 \
}
显然符合本情景条件
10.frag_align_code
s_align_bytes ->s_align->do_align->md_do_align->frag_align_code
void
frag_align_code (int alignment, int max)
{
char *p;
//调用frag_var,记录可变部分,并生成一个新分片
p = frag_var (rs_align_code, MAX_MEM_FOR_RS_ALIGN_CODE, 1,//#define MAX_MEM_FOR_RS_ALIGN_CODE 31
(relax_substateT) max, (symbolS *) 0,//max==0
(offsetT) alignment, (char *) 0);//alignment==2
*p = NOP_OPCODE;// 0x90,nop指令
}
11.frag_var
s_align_bytes ->s_align->do_align->md_do_align->frag_align_code->frag_var
/* Start a new frag unless we have max_chars more chars of room in the
current frag. Close off the old frag with a .fill 0.
Set up a machine_dependent relaxable frag, then start a new frag.
Return the address of the 1st char of the var part of the old frag
to write into. */
char *
frag_var (relax_stateT type, int max_chars, int var, relax_substateT subtype,
symbolS *symbol, offsetT offset, char *opcode)
{
register char *retval;
frag_grow (max_chars);//frag增长max_chars(31)字节,如果当前frag空间不够,会结束当前frag,生成一个新frag
retval = obstack_next_free (&frchain_now->frch_obstack);//返回可以空间首地址
obstack_blank_fast (&frchain_now->frch_obstack, max_chars);//分配max_chars(31)字节
frag_now->fr_var = var;//1(实际上是填充模式长度len)
frag_now->fr_type = type;//rs_align_code类型
frag_now->fr_subtype = subtype;//0(max)
frag_now->fr_symbol = symbol;//NULL
frag_now->fr_offset = offset;//2(alignment)
frag_now->fr_opcode = opcode;//NULL
#ifdef USING_CGEN//忽略
frag_now->fr_cgen.insn = 0;
frag_now->fr_cgen.opindex = 0;
frag_now->fr_cgen.opinfo = 0;
#endif
#ifdef TC_FRAG_INIT//忽略
TC_FRAG_INIT (frag_now);
#endif
as_where (&frag_now->fr_file, &frag_now->fr_line);//记录位置
frag_new (max_chars);//一个frag只有一个可变部分(var),因此结束当前frag,并创建新的frag
return (retval);//返回可变部分首地址
}
总结一下各主要字段的意思,后面会用到
fr_type->对齐类型
fr_subtype->max
fr_var->填充模式长度
fr_offset->alignment
12.返回do_align
s_align_bytes ->s_align->do_align
/* Only make a frag if we HAVE to... */
if (n != 0 && !need_pass_2)//对于数据段等其他情况的处理
{
if (fill == NULL)//没有填充
{
if (subseg_text_p (now_seg))//代码段
frag_align_code (n, max);
else
frag_align (n, 0, max);//其他段
}
else if (len <= 1)//填充长度为1
frag_align (n, *fill, max);
else
frag_align_pattern (n, fill, len, max);//填充长度大于1
}
#ifdef md_do_align
just_record_alignment: ATTRIBUTE_UNUSED_LABEL
#endif
record_alignment (now_seg, n - OCTETS_PER_BYTE_POWER);//记录对齐大小
}
这里的frag_align函数和前面的frag_align_code大同小异,自己看吧
13.返回到s_align_bytes ->s_align
s_align_bytes ->s_align
else
{
//否则有fill pattern
int fill_len;
if (arg >= 0)
fill_len = 1;//fill pattern长度为1
else
fill_len = -arg;//fill pattern长度为-arg,例如.balignw 16,0xff11
if (fill_len <= 1)//长度为1,例如.align 4,'c'
{
char fill_char;
fill_char = fill;
do_align (align, &fill_char, fill_len, max);
}
else
{
char ab[16];
if ((size_t) fill_len > sizeof ab)
abort ();
md_number_to_chars (ab, fill, fill_len);//将填充模式转换成字符串,例如0xff11->"\x11\xff";
do_align (align, ab, fill_len, max);
}
}
demand_empty_rest_of_line ();//结束本行
if (flag_mri)//忽略
mri_comment_end (stop, stopc);
}
阅读(2211) | 评论(0) | 转发(1) |